Optymalizacja jednoczesnych aktualizacji w Postgres

9

Korzystam z równoczesnych zapytań Postgres:

UPDATE foo SET bar = bar + 1 WHERE baz = 1234

Każde zapytanie wpływa na ustaloną liczbę K wierszy i nie mogę znaleźć sposobu na wymuszenie kolejności, w jakiej wiersze są aktualizowane, co powoduje zakleszczenie. Obecnie rozwiązuję ten problem ręcznie, wymuszając wykonanie zamówienia, ale oznacza to, że muszę wykonać o wiele więcej zapytań niż normalnie, jednocześnie zwiększając złożoność wyszukiwania z O (log N + K) do O (K log N).

Czy istnieje sposób na poprawę wydajności bez narażania się na impas? Podejrzewam, że zastąpienie (baz)indeksu (baz, id)indeksem może działać, pod warunkiem że Postgres aktualizuje wiersze w tej samej kolejności, w jakiej je przeskanował, czy jest to podejście warte zastosowania?

Aleksiej Averchenko
źródło
Sugeruję dodanie CREATE TABLEkodu.
ypercubeᵀᴹ

Odpowiedzi:

15

Nie ma ORDER BYw SQL UPDATEpoleceniu. Postgres aktualizuje wiersze w dowolnej kolejności:

Aby uniknąć zakleszczeń z absolutną pewnością, możesz uruchamiać swoje wyciągi w formie szeregowalnej izolacji transakcji . Ale to jest droższe i musisz przygotować się do powtarzania poleceń w przypadku niepowodzenia serializacji.

Najlepszym sposobem jest prawdopodobnie jawne zablokowanie SELECT ... ORDER BY ... FOR UPDATEw podzapytaniu lub samodzielnym SELECTw transakcji - w domyślnym poziomie izolacji „zatwierdzono odczyt”. Cytując Tom Lane w pgsql-general :

Powinno być w porządku --- blokowanie FOR UPDATE jest zawsze ostatnim krokiem w potoku SELECT.

To powinno wykonać zadanie:

BEGIN;

SELECT 1
FROM   foo 
WHERE  baz = 1234
ORDER  BY bar
FOR    UPDATE;

UPDATE foo
SET    bar = bar + 1
WHERE  baz = 1234;

COMMIT;

Wielokolumnowy indeks (baz, bar)może być idealny do wydajności. Ale ponieważ barjest oczywiście bardzo często aktualizowany , indeks jednokolumnowy (baz)może być nawet lepszy. Zależy od kilku czynników. Ile wierszy na baz? Czy możliwe są aktualizacje HOT bez indeksu wielokolumnowego? ...

Jeśli baz jest aktualizowana jednocześnie, wciąż jest mało prawdopodobne rogu przypadek szansa dla konfliktów (na dokumentacji) :

Możliwe jest SELECTpolecenie uruchomione na READ COMMITTED poziomie izolacji transakcji i za pomocą ORDER BYoraz klauzula blokująca, aby zwracać wiersze poza kolejnością. ...

Ponadto, jeśli powinieneś mieć wyjątkowe ograniczenie bar, rozważ DEFERRABLEograniczenie, aby uniknąć unikalnych naruszeń w ramach tego samego polecenia. Powiązana odpowiedź:

Erwin Brandstetter
źródło
1
JEŻELI zamawiam według idlub inną unikalną kolumnę zamiast bar, nie powinno być narożnika ani hitu wydajności, prawda?
Alexei Averchenko
@AlexeiAverchenko: Tak, unikalna kolumna, która nigdy nie jest aktualizowana, byłaby do tego idealna - i indeks wielokolumnowy obejmujący tę kolumnę na drugiej pozycji.
Erwin Brandstetter