Cambia rapidamente la colonna NULL in NOT NULL


11

Ho una tabella con milioni di righe e una colonna che consente valori NULL. Tuttavia, al momento nessuna riga ha un valore NULL per quella colonna (posso verificarlo abbastanza rapidamente con una query). Tuttavia, quando eseguo il comando

ALTER TABLE MyTable ALTER COLUMN MyColumn BIGINT NOT NULL;

la query richiede per sempre relativamente parlando. In realtà ci vogliono tra 10 e 20 minuti, più del doppio rispetto all'aggiunta di un vincolo di controllo. C'è un modo per aggiornare istantaneamente i metadati della tabella per quella colonna, soprattutto perché so che nessuna riga ha un valore NULL per quella colonna?


2
No (o almeno non utilizzando metodi documentati / supportati). Vedi Perché ALTER COLUMN su NOT NULL provoca una massiccia crescita dei file di registro?
Martin Smith,

2
Potrebbe anche essere in attesa di un Sch-Mblocco quando ci vuole "per sempre". Hai guardato per vedere se era in attesa o occupato?
Martin Smith,

@MartinSmith Ho chiarito cosa intendo per sempre . Sto testando questo in un ambiente di sviluppo senza che altre sessioni colpiscano il database. Alla fine si completa. Ma la risposta che hai collegato spiega perché ci vuole così tanto tempo. Se riesci a riformulare il tuo commento come risposta, lo accetterò.
Joseph Daigle,

Risposte:


12

La risposta di @ ypercube lo gestisce parzialmente solo come modifica dei metadati.

L'aggiunta del vincolo con NOCHECKsignifica che non sarà necessario leggere le righe per verificarlo e, se si parte da una posizione in cui la colonna non contiene NULLvalori (e se si conosce che non verrà aggiunto nessuno tra il controllo e l'aggiunta del vincolo), poiché il vincolo impedisce la NULLcreazione di valori futuri INSERTo UPDATEoperazioni, funzionerà.

L'aggiunta del vincolo può comunque avere un impatto sulle transazioni simultanee. L' ALTER TABLEavrà bisogno di acquisire un Sch-Mblocco di prima. Durante l'attesa, tutti gli altri accessi alle tabelle verranno bloccati come descritto qui .

Una volta Sch-Macquisito il blocco, l'operazione dovrebbe essere piuttosto rapida.

Un problema con questo è che anche se si conosce che la colonna in realtà non ha NULLs il vincolo non è attendibile dal Query Optimizer, il che significa che i piani possono essere non ottimali.

CREATE TABLE T (X INT NULL)

INSERT INTO T 
SELECT ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM master..spt_values

ALTER TABLE T WITH NOCHECK
  ADD  CONSTRAINT X_NOT_NULL 
    CHECK (X IS NOT NULL) ; 

SELECT *
FROM T 
WHERE X NOT IN (SELECT X FROM T)

Piano

Confronta questo con il più semplice

ALTER TABLE T ALTER COLUMN X INT NOT NULL

SELECT *
FROM T 
WHERE X NOT IN (SELECT X FROM T)

Piano

Un possibile problema che potresti riscontrare con l'alterazione della definizione di colonna in questo modo è che non solo è necessario leggere tutte le righe per verificare che soddisfino la condizione, ma può anche finire per eseguire effettivamente gli aggiornamenti registrati alle righe .

Una possibile casa a metà strada potrebbe essere quella di aggiungere il vincolo di controllo WITH CHECK. Questo sarà più lento di WITH NOCHECKquanto deve leggere tutte le righe ma consente all'ottimizzatore di query di fornire il piano più semplice nella query sopra e dovrebbe evitare il possibile problema degli aggiornamenti registrati.


7

È possibile, invece di modificare la colonna, aggiungere un CHECKvincolo di tabella con l' NOCHECKopzione:

ALTER TABLE MyTable WITH NOCHECK
  ADD  CONSTRAINT MyColumn_NOT_NULL 
    CHECK (MyColumn IS NOT NULL) ;

1
Ciò impedirebbe futuri aggiornamenti o inserimenti che rendono la colonna NULLma non potrebbe essere utilizzato da Query Optimizer.
Martin Smith,

@MartinSmith Oh sì, ho appena letto la risposta e i commenti nella domanda simile: Come si aggiunge una colonna NOT NULL a una tabella di grandi dimensioni in SQL Server? Per favore, aggiungi una risposta con i problemi o una soluzione migliore e rimuoverò la mia.
ypercubeᵀᴹ

2
Non ho una soluzione migliore. Ho votato questo perché fornisce una soluzione parziale. Se tutto ciò che l'OP vuole fare è impedire che i dati non validi funzionino (e dovrebbe essere più veloce di ALTER COLUMNcome una volta Sch-Macquisito il blocco, non è necessario sottoporre a scansione le righe). Solo sottolineando che non è proprio lo stesso (ad esempio se utilizzato in una NOT INquery il piano sarà più complesso)
Martin Smith,
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.