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.