Ottimizzazione degli aggiornamenti simultanei in Postgres


9

Sto eseguendo query Postgres simultanee come questa:

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

Ogni query influisce sul numero K fisso di righe e non riesco a trovare un modo per far rispettare l'ordine in cui le righe vengono aggiornate, finisco con deadlock. Attualmente risolvo il problema applicando manualmente l'ordine, ma ciò significa che devo eseguire molte più query di quante farei normalmente aumentando la complessità della ricerca da O (log N + K) a O (K log N).

C'è un modo per migliorare le prestazioni senza diventare vulnerabili agli deadlock? Ho il sospetto che la sostituzione (baz)dell'indice con l' (baz, id)indice possa funzionare a condizione che Postgres aggiorni le righe nello stesso ordine in cui le ha scansionate, vale la pena perseguire questo approccio?


Ti suggerisco di aggiungere il CREATE TABLEcodice.
ypercubeᵀᴹ

Risposte:


15

Non esiste ORDER BYun SQL UPDATEcomando. Postgres aggiorna le righe in ordine arbitrario:

Per evitare deadlock con assoluta certezza, è possibile eseguire le dichiarazioni in isolamento di transazione serializzabile . Ma è più costoso e devi prepararti a ripetere i comandi in caso di errore di serializzazione.

Il miglior modo di agire è probabilmente quello di bloccare esplicitamente SELECT ... ORDER BY ... FOR UPDATEin una sottoquery o uno standalone SELECTin una transazione - nel livello di isolamento predefinito "read commit". Citando Tom Lane su pgsql-general :

Dovrebbe andare tutto bene --- il blocco FOR UPDATE è sempre l'ultimo passo nella pipeline SELECT.

Questo dovrebbe fare il lavoro:

BEGIN;

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

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

COMMIT;

Un indice a più colonne (baz, bar)potrebbe essere perfetto per le prestazioni. Ma dal momento che barè ovviamente aggiornato molto , un indice a colonna singola (baz)potrebbe essere ancora migliore. Dipende da un paio di fattori. Quante righe per baz? Gli aggiornamenti HOT sono possibili senza l'indice multicolonna? ...

Se baz viene aggiornato contemporaneamente, v'è ancora un improbabile angolo caso possibilità di conflitti (per la documentazione) :

È possibile che un SELECTcomando venga eseguito a READ COMMITTED livello di isolamento della transazione e utilizzi ORDER BYe una clausola di blocco per restituire le righe fuori servizio. ...

Inoltre, se si dovrebbe avere un vincolo unico che coinvolge bar, considerare un DEFERRABLEvincolo per evitare violazioni univoche all'interno dello stesso comando. Risposta correlata:


1
Se sto ordinando da ido qualche altra colonna unica invece di bar, non dovrebbe esserci un caso d'angolo o un hit da prestazione, giusto?
Alexei Averchenko,

@AlexeiAverchenko: Sì, una colonna unica che non viene mai aggiornata sarebbe perfetta per questo - e un indice a più colonne che include questa colonna in seconda posizione.
Erwin Brandstetter,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.