Altere rapidamente a coluna NULL para NOT NULL

11

Eu tenho uma tabela com milhões de linhas e uma coluna que permite valores nulos. No entanto, nenhuma linha atualmente possui um valor NULL para essa coluna (posso verificar isso rapidamente com uma consulta). No entanto, quando executo o comando

ALTER TABLE MyTable ALTER COLUMN MyColumn BIGINT NOT NULL;

a consulta leva uma eternidade relativamente falando. Na verdade, leva entre 10 e 20 minutos, mais do que o dobro da adição de uma restrição de verificação. Existe uma maneira de atualizar instantaneamente os metadados da tabela para essa coluna, principalmente porque eu sei que nenhuma linha tem um valor NULL para essa coluna?

Joseph Daigle
fonte
2
Não (ou pelo menos não usando métodos documentados / suportados). Consulte Por que ALTER COLUMN para NOT NULL causa um grande crescimento no arquivo de log?
Martin Smith
2
Também pode estar aguardando um Sch-Mbloqueio quando "durar para sempre". Você olhou para ver se estava esperando ou ocupado?
Martin Smith
@MartinSmith Esclarei o que quero dizer com sempre . Estou testando isso em um ambiente de desenvolvimento sem outras sessões atingindo o banco de dados. Eventualmente, é concluído. Mas a resposta que você vinculou explica por que demora tanto tempo. Se você pode reformular seu comentário como resposta, eu o aceito.
Joseph Daigle 29/08/2013

Respostas:

12

A resposta do @ ypercube gerencia isso parcialmente, pois apenas os metadados são alterados.

Adicionar a restrição NOCHECKsignifica que nenhuma linha precisará ser lida para verificá-la e, se você estiver começando em uma posição em que a coluna não contém NULLvalores (e se você souber que nenhuma será adicionada entre verificar e adicionar a restrição), como a restrição impede a NULLcriação de valores do futuro INSERTou das UPDATEoperações, isso funcionará.

A adição da restrição ainda pode ter impacto nas transações simultâneas. A ALTER TABLEnecessidade de adquirir um Sch-Mbloqueio primeiro. Enquanto aguarda, todos os outros acessos à tabela serão bloqueados conforme descrito aqui .

Uma vez que o Sch-Mbloqueio é adquirido, a operação deve ser bastante rápida.

Um problema com isso é que, mesmo que você saiba que a coluna não possui, NULLa restrição não é confiável pelo otimizador de consultas, o que significa que os planos podem ficar abaixo do ideal.

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)

Plano

Compare isso com o mais simples

ALTER TABLE T ALTER COLUMN X INT NOT NULL

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

Plano

Um possível problema que você pode encontrar ao alterar a definição da coluna dessa maneira é que ela não apenas precisa ler todas as linhas para verificar se elas atendem à condição, mas também pode acabar realmente executando atualizações registradas nas linhas .

Uma casa possível a meio caminho pode ser adicionar a restrição de verificação WITH CHECK. Isso será mais lento do WITH NOCHECKque o necessário para ler todas as linhas, mas permite que o otimizador de consultas forneça o plano mais simples na consulta acima e evite o possível problema de atualizações registradas.

Martin Smith
fonte
7

Você pode, em vez de alterar a coluna, adicionar uma CHECKrestrição de tabela com a NOCHECKopção:

ALTER TABLE MyTable WITH NOCHECK
  ADD  CONSTRAINT MyColumn_NOT_NULL 
    CHECK (MyColumn IS NOT NULL) ;
ypercubeᵀᴹ
fonte
1
Isso impediria futuras atualizações ou inserções que compõem a coluna, NULLmas não poderiam ser usadas pelo otimizador de consultas.
Martin Smith
@MartinSmith Ah, sim, acabei de ler a resposta e os comentários na pergunta semelhante: Como você adiciona uma coluna NOT NULL a uma tabela grande no SQL Server? Por favor, adicione uma resposta com os problemas ou uma solução melhor e eu removerei a minha.
precisa saber é o seguinte
2
Eu não tenho uma solução melhor. Votei isso porque ele fornece uma solução parcial. Se tudo o que o OP deseja é impedir que dados inválidos funcionem (e deve ser mais rápido do ALTER COLUMNque quando a Sch-Mtrava é adquirida, isso não precisa varrer as linhas). Apenas indicando que não é bem a mesma coisa (por exemplo, se usado em uma NOT INconsulta o plano será mais complexo)
Martin Smith