PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Aggiornare le righe del database senza bloccare la tabella in PostgreSQL 9.2

MVCC

Innanzitutto, se le "operazioni normali" consistono in SELECT query, il modello MVCC se ne occuperà automaticamente. UPDATE non blocca SELECT e viceversa. SELECT vede solo i dati impegnati (o ciò che è stato fatto nella stessa transazione), quindi il risultato del grande UPDATE rimane invisibile ad altre transazioni fino al completamento (impegnato).

Prestazioni/gonfiamento

Se non hai altri oggetti che fanno riferimento a quella tabella,
e non hai operazioni di scrittura simultanee (che andrebbero perse!),
e puoi permetterti un lucchetto esclusivo molto breve sul tavolo,
e hai spazio su disco aggiuntivo, ovviamente:
Potresti ridurre al minimo il blocco creando una versione aggiornata della tabella in background. Assicurati che abbia tutto per essere un sostituto immediato, quindi rilascia l'originale e rinomina il duplicato.

CREATE TABLE tbl_new (LIKE tbl_org INCLUDING CONSTRAINTS);

INSERT INTO tbl_new 
SELECT col_a, col_b, array[col] aS col_c
FROM   tbl_org;

Sto usando CREATE TABLE (LIKE .. INCLUDING CONSTRAINTS) , perché (citando qui il manuale):

I vincoli non nulli vengono sempre copiati nella nuova tabella. CHECK i vincoli verranno copiati solo se INCLUDING CONSTRAINTS è specificato; altri tipi di vincoli non verranno mai copiati.

Assicurati che la nuova tabella sia pronta. Quindi:

DROP tbl_org;
ALTER TABLE tbl_new RENAME TO tbl_org;

Risulta in una finestra temporale molto breve, in cui il tavolo è bloccato esclusivamente.

Si tratta davvero solo di prestazioni. Crea una nuova tabella senza alcun rigonfiamento piuttosto rapidamente. Se hai chiavi o viste esterne, puoi comunque seguire quella strada, ma devi preparare uno script per rilasciare e ricreare questi oggetti, creando potenzialmente blocchi esclusivi aggiuntivi.

Scritture simultanee

Con operazioni di scrittura simultanee, tutto ciò che puoi fare è dividere l'aggiornamento in blocchi. Non puoi farlo in una singola transazione, poiché i blocchi vengono rilasciati solo alla fine di una transazione.

Potresti utilizzare dblink , che può avviare transazioni indipendenti su un altro database, incluso se stesso. In questo modo potresti fare tutto in un unico DO istruzione o una funzione plpgsql con un ciclo. Ecco una risposta vagamente correlata con ulteriori informazioni su dblink:

  • Elimina o crea database dalla procedura memorizzata in PostgreSQL

Il tuo approccio con i cursori

Un cursore all'interno della funzione non ti comprerà niente . Qualsiasi funzione viene racchiusa automaticamente in una transazione e tutti i blocchi vengono rilasciati solo al termine della transazione. Anche se hai utilizzato CLOSE cursor (cosa che non fai) libererebbe solo alcune risorse, ma non rilasciare i blocchi acquisiti sul tavolo. Cito il manuale:

CLOSE chiude il portale sottostante un cursore aperto. Questo può essere utilizzato per rilasciare risorse prima della fine della transazione o per liberare la variabile cursore da riaprire.

Dovresti eseguire separatamente transazioni o (ab)usa dblink che lo fa per te.