Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Aktualizacja tabeli, szybciej niż INSERT ... ON DUPLICATE KEY UPDATE
BlackPig
post
Post #1





Grupa: Zarejestrowani
Postów: 9
Pomógł: 0
Dołączył: 27.02.2009

Ostrzeżenie: (10%)
X----


Witam, mam problem, który nie dał mi spać dzisiejszej nocy, dotyczący aktualizacji bazy danych.
Chodzi o sytuację, kiedy stale aktualizuję tabelę, która ma klucz glówny. Jak to przy aktualizacji,
mogą pojawiać się nowe dane, albo być poprawiane stare.
Dotąd robiłem to tak:
INSERT into tabela ON DUPLICATE KEY UPDATE....
Problem, polega na tym, że przy dużej liczbie danych zaczyna się zamulać...
Powodem może być specyika aktualizacji, w której orientacyjnie w 99% wypadków wykonywany jest UPDATE,
a INSERT bardzo rzadko.
Więc w praktyce moja metoda najpierw próbuje robić INSERT, który w 99% przypadków sie nie udaje
(okazuje się to po sprawdzeniu klucza głównego, w bardzo długiej liście), następnie wykonuje UPDATE, który sie udaje.

Moje pytanie, czy da się jakoś sprytnie odwrócić kolejność działań - coś w stylu:

UPDATE tabela (99% się udaje)
ON nie_było_co_updatować INSERT (wyjątek dla 1% wyjątków)

Zamiast:

INSERT INTO tabela (1% się udaje)
ON DUPLICATE KEY UPDATE (wyjątek dla 99%)

To jakiś tam pomysł, ale każda inna sugestia przyspieszająca aktualizację w takim wypadku byłaby mile widziana smile.gif


--------------------
PROGRAMISTA
Go to the top of the page
+Quote Post
phpion
post
Post #2





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Wrzuć sobie dane do tabeli tymczasowej o strukturze identycznej ze strukturą tabeli właściwej. Będziesz miał wówczas 2 tabele: 1 z aktualnymi danymi, 2 z danymi do zaimportowania. Aktualizację tabeli właściwej zrobisz bardzo szybko poprzez zapytania z wykorzystaniem EXISTS (aktualizacja) oraz NOT EXISTS (wstawienie). Coś w tym stylu:
  1. INSERT INTO wlasciwa (pole) SELECT (pole) FROM tymczasowa WHERE NOT EXISTS (SELECT pole FROM wlasciwa WHERE id = tymczasowa.id)

Możliwe, że gdzieś się machnąłem w powyższym zapytaniu, ale ideę załapiesz.
Go to the top of the page
+Quote Post
BlackPig
post
Post #3





Grupa: Zarejestrowani
Postów: 9
Pomógł: 0
Dołączył: 27.02.2009

Ostrzeżenie: (10%)
X----


Dzięki za pomoc winksmiley.jpg
Rozumiem, że rozwiązanie bazuje na tym, że EXISTS/NOEXISTS ma działać znacznie szybciej niż DUPLICATE KEY - bo tutaj w sumie wykonujemy i wstawianie do tabeli tymczasowej (szybsze bo jest pusta), i potem jeszcze raz przekłądamy z tymczasowej do zwykłej hurtowo (ale na podobnej zasadzie)... też sprawdzajac powtórzenia...
Na razie udało mi się wyspać i uzyskać dobrą szybkość przez odśmiecenie projektu z kupy nąszalandzkich rozwiązań (złe przyzwyczajenia z małych CMSów), typu 5 razy za duże varchary, robienie pojedynczych query w każdej pętli winksmiley.jpg Rozwiązania, więc narazie nie testuję - miałbym sporo do zmiany bo kilka tam tych tabel jest - zostawię to sobie jako ASA w rękawie na wypadek gdyby się znowu zmuliło smile.gif
Ale jeszcze raz dzięki bo Twój post spowodował, że poczytałem o tabelach tymczasowych i memory z którymi nie miałem dotąd do czynienia, a dobrze o nich wiedzieć winksmiley.jpg


--------------------
PROGRAMISTA
Go to the top of the page
+Quote Post
maly_swd
post
Post #4





Grupa: Zarejestrowani
Postów: 744
Pomógł: 118
Dołączył: 14.02.2009
Skąd: poziome

Ostrzeżenie: (0%)
-----


a nie mozesz robic tak:
1. updatujesz
2. sprawdzasz mysql_affected_rows jesli jest 0 - to znaczy ze nic sie nie zupdatowalo i trzeba wykonac INSERTA

inne rozwiazanie to pobrac sobie do tablicy ID (to co masz kluczem glownym) i sprawdzac if($tablica[$klucz]) to znaczy ze trzeba update, else INSERT


--------------------
śmieszne obrazki
Kryzys: Ser jem spleśniały, wino piję stare i samochód mam bez dachu..
Go to the top of the page
+Quote Post
Mchl
post
Post #5





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


Cytat(maly_swd @ 23.02.2010, 12:40:49 ) *
a nie mozesz robic tak:
1. updatujesz
2. sprawdzasz mysql_affected_rows jesli jest 0 - to znaczy ze nic sie nie zupdatowalo i trzeba wykonac INSERTA


Jak jednym zapytaniem wstawiamy jeden wiersz to może być. Gorzej jak wstawianych jest 500, z czego 250 na insert, 250 na update.
Go to the top of the page
+Quote Post
erix
post
Post #6





Grupa: Moderatorzy
Postów: 15 467
Pomógł: 1451
Dołączył: 25.04.2005
Skąd: Szczebrzeszyn/Rzeszów




Zawsze można spróbować napisać do tego procedurę.


--------------------

ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW!
Go to the top of the page
+Quote Post
maly_swd
post
Post #7





Grupa: Zarejestrowani
Postów: 744
Pomógł: 118
Dołączył: 14.02.2009
Skąd: poziome

Ostrzeżenie: (0%)
-----


Cytat(Mchl @ 23.02.2010, 13:09:22 ) *
Jak jednym zapytaniem wstawiamy jeden wiersz to może być. Gorzej jak wstawianych jest 500, z czego 250 na insert, 250 na update.


Kolega napisal: "Powodem może być specyika aktualizacji, w której orientacyjnie w 99% wypadków wykonywany jest UPDATE,
a INSERT bardzo rzadko.", Wiec przyjmujemy ze sa robione same UPDATY a INSERT to przypadek:)

Jest jeszcze: REPLACE INTO ... ale nie wiem jak z jego szybkoscia

Ten post edytował maly_swd 23.02.2010, 15:33:40


--------------------
śmieszne obrazki
Kryzys: Ser jem spleśniały, wino piję stare i samochód mam bez dachu..
Go to the top of the page
+Quote Post
Mchl
post
Post #8





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


Cytat(maly_swd @ 23.02.2010, 15:32:14 ) *
Kolega napisal: "Powodem może być specyika aktualizacji, w której orientacyjnie w 99% wypadków wykonywany jest UPDATE,
a INSERT bardzo rzadko.", Wiec przyjmujemy ze sa robione same UPDATY a INSERT to przypadek:)


Tak napisał, ale nie wiemy, czy w jednym zapytaniu robi to dla wielu wierszy czy dla jednego. Zapewne dla jednego, ale pewności nie mamy.

Cytat
Jest jeszcze: REPLACE INTO ... ale nie wiem jak z jego szybkoscia


Jeszcze gorzej: REPLACE = DELETE + INSERT dla wszystkich wierszy.

Jeżeli tabela jest InnoDB, a wykonywanych jest wiele zapytań INSERT/UPDATE jedno po drugim (np w pętli) to pomóc może wpakowanie całości do jednej transakcji i zatwierdzenie wszystkiego jednym COMMITEM.
Go to the top of the page
+Quote Post
maly_swd
post
Post #9





Grupa: Zarejestrowani
Postów: 744
Pomógł: 118
Dołączył: 14.02.2009
Skąd: poziome

Ostrzeżenie: (0%)
-----


Cytat
Tak napisał, ale nie wiemy, czy w jednym zapytaniu robi to dla wielu wierszy czy dla jednego. Zapewne dla jednego, ale pewności nie mamy.

W sumie masz racje;)

Cytat
Jeszcze gorzej: REPLACE = DELETE + INSERT dla wszystkich wierszy.

Kurcze, czlowiek uczy sie cale zycie:) - a mozesz mi podac linko do wyjasnienia tego:)
Czyli insert z on duplicate jest szybszy od replaca?



--------------------
śmieszne obrazki
Kryzys: Ser jem spleśniały, wino piję stare i samochód mam bez dachu..
Go to the top of the page
+Quote Post
Mchl
post
Post #10





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

Ostrzeżenie: (0%)
-----


http://dev.mysql.com/doc/refman/5.0/en/replace.html

Teoretycznie tak, bo przynajmniej część wierszy zostanie zaktualizowana prze UPDATE.
Go to the top of the page
+Quote Post
BlackPig
post
Post #11





Grupa: Zarejestrowani
Postów: 9
Pomógł: 0
Dołączył: 27.02.2009

Ostrzeżenie: (10%)
X----


Widzę, że tutaj dyskusja rozgorzała winksmiley.jpg Chociaż, że wszystko narazie działa dobrze po staremu to się włączę z powrotem:
Cytat
1. updatujesz
2. sprawdzasz mysql_affected_rows jesli jest 0 - to znaczy ze nic sie nie zupdatowalo i trzeba wykonac INSERTA

nie wygląda mi to na dobre rozwiązanie nie dlatego, że nie wstawiam po jednym, ale z innego powodu:
mysql_affected_rows zwraca liczbę wierszy rzeczywiście zmienionych - ja pobieram dane cyklicznie z XML.
W prawdzie system z którego pobieram jest mądry i w jednym XML udostępnia mi tylko dane dotyczące tych meczów, w których coś się zmieniło, to niestety jeden XML zapisany jest w kilku tabelach, więc to że zmieniło się w XML nie znaczy, ze jest co updatować we wszystkich tabelach, na których zapytania i tak wykonam.... Może być więc tak, ze ktoś koryguje tylko literówkę w nazwisku strzelca bramki, a ja i tak muszę updatować całą strukturę... Wtedy podany sposób działa tak smile.gif
1. update tabela z meczami
dane się nie zmieniły, więc mysql_affected_rows==0
w takim razie:
2. instert into tabela z meczami i mamy error duplicate key smile.gif


--------------------
PROGRAMISTA
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 19.08.2025 - 06:31