Mam pytanie związane z wydajnością. Załóżmy, że mam użytkownika o imieniu Michael. Weź następujące zapytanie:
UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
Czy zapytanie faktycznie wykona aktualizację, nawet jeśli jest aktualizowana do tej samej wartości? Jeśli tak, jak mogę temu zapobiec?
postgresql
performance
update
postgresql-performance
OneSneakyMofo
źródło
źródło
Odpowiedzi:
Ze względu na model Postgres MVCC i zgodnie z regułami SQL,
UPDATE
dla każdego wiersza zapisuje nową wersję wiersza, która nie jest wykluczona wWHERE
klauzuli.Ma to mniej lub bardziej znaczący wpływ na wydajność, bezpośrednio i pośrednio. „Puste aktualizacje” mają taki sam koszt na wiersz jak każda inna aktualizacja. Wystrzeliwują wyzwalacze (jeśli są obecne), jak każda inna aktualizacja, muszą być zalogowane w WAL i wytwarzają martwe wiersze nadymające tabelę i powodujące więcej pracy na
VACUUM
później, jak każda inna aktualizacja.Indeksuje wpisy i kolumny TOASTed, w których żadna z zaangażowanych kolumn nie jest zmieniana, nie może pozostać taka sama, ale dotyczy to każdego zaktualizowanego wiersza. Związane z:
Prawie zawsze dobrym pomysłem jest wykluczenie takich pustych aktualizacji (gdy istnieje rzeczywista szansa, że może się zdarzyć). W swoim pytaniu nie podałeś definicji tabeli (co zawsze jest dobrym pomysłem). Musimy założyć, że
first_name
może być NULL (co nie byłoby zaskoczeniem dla „imienia”), dlatego zapytanie musi używać porównania NULL-safe :Jeśli
first_name IS NULL
przed aktualizacją, test z justfirst_name <> 'Michael'
będzie miał wartość NULL i jako taki wykluczy wiersz z aktualizacji. Podstępny błąd. Jeśli kolumna jest zdefiniowanaNOT NULL
, użyj prostej kontroli równości, ponieważ jest to nieco tańsze.Związane z:
źródło
Indexes entries and TOASTed columns where none of the involved columns are changed can stay the same
Ale czy nie trzeba ich aktualizować, aby wskazywały nową lokalizację rzędu?rollback
, obsługa migawek, zarządzanie zamkami, WAL, co nie ...ORM, podobnie jak oferta Ruby on Rail, odracza wykonanie, które oznacza rekord jako zmieniony (lub nie), a następnie w razie potrzeby lub wywołania, a następnie przesyła zmianę do bazy danych.
PostgreSQL to baza danych, a nie ORM. Zmniejszyłoby to wydajność, gdyby zajęło trochę czasu sprawdzenie, czy nowa wartość jest taka sama jak zaktualizowana wartość w zapytaniu.
W związku z tym zaktualizuje wartość bez względu na to, czy jest taka sama jak nowa wartość, czy nie.
Jeśli chcesz temu zapobiec, możesz użyć kodu takiego jak sugerowany w odpowiedzi Max Vernon.
źródło
Możesz po prostu dodać do
where
klauzuli:Jeśli
first_name
zdefiniowano jakoNOT NULL
,OR first_name IS NULL
część można usunąć.Warunek:
można również napisać bardziej elegancko, ponieważ (w odpowiedzi Erwina):
źródło
NULL
@erwinZ punktu widzenia bazy danych
Odpowiedź na twoje pytanie brzmi TAK. Aktualizacja odbędzie się. Baza danych nie sprawdza poprzedniej wartości, ustawia tylko nową wartość.
Ponieważ dzieje się to w pamięci (i zostanie zapisane w plikach danych dopiero po wydaniu zatwierdzenia), wydajność nie będzie stanowić problemu.
Z perspektywy ORM
Zwykle będziesz mieć Obiekt reprezentujący pojedynczy wiersz bazy danych (może być o wiele bardziej złożony, ale bądźmy prostsze). Ten obiekt jest zarządzany w pamięci (na poziomie serwera aplikacji) i tylko najnowsza zatwierdzona wersja tego obiektu faktycznie trafi do bazy danych w pewnym momencie.
To może tłumaczyć inne zachowanie.
Nie porównujmy teraz statku towarowego z drukarką 3D. Fakt, że możesz wysyłać drukarki 3D za pomocą statków towarowych, nie oznacza, że może istnieć jakiekolwiek porównanie między nimi.
Cieszyć się!
Mam nadzieję, że wyjaśniło to niektóre pojęcia.
źródło