2013-10-22 12 views
12

Penso di aver letto da qualche parte che l'esecuzione di un ALTER TABLE foo ADD COLUMN baz text su un database Postgres non causa un blocco di lettura o scrittura. L'impostazione di un valore predefinito causa il blocco, ma consentire un valore predefinito predefinito impedisce un blocco.L'aggiunta di una colonna nulla a una tabella Postgres causa un blocco?

Non riesco a trovare questo nella documentazione, però. Qualcuno può indicare un luogo che dice, in modo definitivo, se questo è vero o no?

risposta

10

I diversi tipi di blocchi e quando vengono utilizzati sono menzionati nel documento in Table-level Locks. A proposito di ALTER TABLE, si dice solo che può acquisire un blocco SHARE UPDATE EXCLUSIVE o ACCESS EXCLUSIVE.

Ma in realtà, le versioni correnti di postgres accettano Access Exclusive Locks per tutte le varianti di questo comando, quindi non è vero che letture contemporanee possono accadere contemporaneamente in certi casi.

È facile controllare il codice sorgente perché in vari casi è prevista una funzione dedicata a stabilire il livello di blocco necessario per questo comando. Si vedano i commenti in src/backend/commands/tablecmds.c:

/* 
* AlterTableGetLockLevel 
* 
* Sets the overall lock level required for the supplied list of subcommands. 
* Policy for doing this set according to needs of AlterTable(), see 
* comments there for overall explanation. 
* 
* Function is called before and after parsing, so it must give same 
* answer each time it is called. Some subcommands are transformed 
* into other subcommand types, so the transform must never be made to a 
* lower lock level than previously assigned. All transforms are noted below. 
* 
* Since this is called before we lock the table we cannot use table metadata 
* to influence the type of lock we acquire. 
* 
* There should be no lockmodes hardcoded into the subcommand functions. All 
* lockmode decisions for ALTER TABLE are made here only. The one exception is 
* ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt 
* and does not travel through this section of code and cannot be combined with 
* any of the subcommands given here. 
*/ 

LOCKMODE 
AlterTableGetLockLevel(List *cmds) 
{ 
    /* 
    * Late in 9.1 dev cycle a number of issues were uncovered with access to 
    * catalog relations, leading to the decision to re-enforce all DDL at 
    * AccessExclusiveLock level by default. 

La funzione ha una certa logica per prendere le serrature più deboli ma è disabilitata nella sua forma attuale per tornare AccessExclusiveLock in tutti i casi.

+0

Questo è fantastico - non mi è mai venuto in mente di guardare la fonte, e se avesse avuto, non avrei saputo dove guardare. Sorprendentemente leggibile. Sto guardando attraverso di esso per vedere se riesco a trovare prove che è solo un breve blocco per l'aggiunta di colonne nullable, ma non so abbastanza per dirlo con certezza. Forse qualcosa in ATExecAddColumn? https://github.com/postgres/postgres/blob/master/src/backend/commands/tablecmds.c#L4383 – jpadvo

+2

@jpadvo: l'aggiunta di colonne nullable o non annullabili richiede lo stesso tipo di blocco. Se viene fornito un valore predefinito, è sempre lo stesso blocco ma è trattenuto più a lungo perché deve effettivamente scrivere il valore in ogni riga della tabella. –

10

L'aggiunta di una nuova colonna null bloccherà la tabella per pochissimo tempo poiché non è necessario riscrivere tutti i dati sul disco. Aggiungendo la colonna con il valore predefinito, è necessario che PostgreSQL crei nuove versioni di tutte le righe e le memorizzi sul disco. E durante quel tempo la tabella sarà bloccata.

Pertanto, quando è necessario aggiungere una colonna con valore predefinito alla tabella grande, si consiglia di aggiungere prima il valore null e quindi aggiornare tutte le righe in piccole parti. In questo modo eviterete un carico elevato su disco e consentirete a autovacuum di eseguire il proprio lavoro in modo da non dover raddoppiare le dimensioni del tavolo.

7

http://www.postgresql.org/docs/current/static/sql-altertable.html#AEN57290

"Aggiunta di una colonna con un predefinito non nullo oppure cambiare il tipo di una colonna esistente richiederà l'intera tabella e indici essere riscritto."

Quindi la documentazione specifica solo quando la tabella non viene riscritta. Ci sarà sempre un blocco, ma sarà molto breve nel caso in cui la tabella non debba essere riscritta.

+0

WARN: in 9.4 o superiore: l'aggiunta di una colonna con una clausola DEFAULT o la modifica del tipo di una colonna esistente richiederà la riscrittura dell'intera tabella e dei relativi indici. –