DML – update -aktualizacja danych w bazie

Ręczna aktualizacja danych w bazie to najniebezpieczniejsza operacja w RDBMS moim zdaniem. Należy tą operację przeprowadzić z szczególną starannością. Wynika to z faktu iż podmieniamy najczęściej wartości na takie które spełniają zależności w bazie. Gdy napiszemy źle pytanie aktualizujące możemy zmodyfikować dużą ilość wierszy co będzie później trudne do wykrycia. Powinniśmy raczej trzymać się zasady iż nie updatetuje się pól kluczy.
Składnia polecenia jest podobna do polecenia insert

update tabela set kolumna = nowa_wartosc, kolumna_2 = nowa_wartosc;

Powyższe zapytanie zmodyfikuje nam wszystkie wiersze tabeli. Podobnie jak w przypadku delete i select możemy korzystać z warunków:

update tabela set kolumna=1 where kolumna_2 = 'jakas wartosc';

np:

update przyjaciele set wynagrodzenie = wynagrodzenie * 1,1 where plec = 1;

czyli każdy z naszych męskich przyjaciół dostał 10% podwyżki.
Tak więc podobnie jak w przypadku delete filtry możemy stosować bez ograniczeń.

Czasem zachodzi potrzeba aktualizacji danych na podstawie jakiegoś zapytania. Niestety implementacje nie są jednorodne. Najlepiej to wygląda na Oracle.

update przyjaciele p set wynagrodzenie = (select k.wynagrodzenie from przyjaciele_kopia k where k.id = p.id)

chcąc na Oraclu w ten sposób zaktualizować kilka kolumn za jednym zamachem:

update przyjaciele p set (wynagrodzenie,kolor) = (select k.wynagrodzenie,k.kolor from przyjaciele_kopia k where k.id = p.id)

Wygląda to dość podobnie do zapytania skorelowanego.
Jednak związany jest z tym mały żarcik:

update przyjaciele p set (wynagrodzenie,kolor) = (select k.wynagrodzenie,k.kolor from przyjaciele_kopia k where k.id = p.id) where p.kolor=0

aktualizacja wynagrodzenia dla przyjaciol koloru 0. Teraz załóżmy że tabela przyjaciele_kopia jest nie kompletna i zawiera tylko połowe przyjaciół z kolorem = 0. To co zrobi Oracle jest dość nie miłe, dla reszty przyjaciół koloru 0 przypisze null do wynagrodzenia. W zapytaniu głównym po za zapytaniem skorelowanym należy umieścić odpowiednie warunki. Działa to tak jakby w zapytaniu skorelowanym było ukryte wiązanie a w głównym filtr. Dla niedopasowanych wartości ustawiane są nulle.

W mssq taki update można przeprowadzić za pomocą inner join’a

UPDATE przyjaciele
SET kolor=10
FROM przyjaciele p
INNER JOIN przyjaciele_kopia k
ON p.id = k.id

Tutaj już szczęśliwie nie ma niespodzianek związanych z korelacją.

Teraz trochę o tym jak taka operacja się odbywa. Tak naprawdę update to delete połączony z insertem.
Więc możemy załapać się na triggery reagujące zarówno na insert i delete. Dlatego też aktualizacja wierszy powinna skupiać w sobie wiedzę odnośnie insertowania i usuwania danych. Nie mniej trzeba sprawdzić (w dokumentacji) jak reaguje dany RDBMS na aktualizacje.

Teraz mała kwestia optymalizacyjna:
zakładając iż mamy tabele 130k wierszy nie poindeksowaną:

update przyjaciele set wynagrodzenie = 0 where kolor is null or plec is null or wiek is null

lepiej zapisać jako:
update przyjaciele set wynagrodzenie = 0 where kolor is null;
update przyjaciele set wynagrodzenie = 0 where plec is null;
update przyjaciele set wynagrodzenie = 0 where wiek is null;

Sprawdziłem ostatnio to empirycznie. W pierwszym przypadku czas wykonania wzrósł ponad 10 krotnie w stosunku do kilku zapytań z jednym filtrem.

Leave a Reply

Your email address will not be published. Required fields are marked *

8 + eighteen =