Estou tentando atualizar uma tabela com cerca de 6,5 milhões de linhas em um tempo razoável, mas estou tendo alguns problemas. Estamos adicionando uma nova coluna a uma tabela existente e, em seguida, definindo um valor para todas as linhas com base nos dados de uma coluna em outra tabela.
UPDATE TOP (20000) c
SET c.NewColumn = ISNULL(p.Col1, p.Col2)
FROM dbo.Child c
INNER JOIN dbo.Parent p on c.FKId = p.Id
WHERE c.NewColumn IS NULL
em um loop, como este artigo . A atualização ainda estava em execução após 2,5 horas. Eu estou querendo saber se desabilitar os índices dbo.Child
causaria um impacto. NewColumn não tem índices, nem terá, mas existem outros índices (cerca de 5) emdbo.Child
O SQL Server é inteligente o suficiente para ver que não precisa atualizar os outros índices (já que eles não fazem parte do UPDATE), ou nos beneficiaríamos desabilitando temporariamente os índices enquanto fazemos as instruções de atualização?
Este é o SQL Server 2012, mas o banco de dados em questão está no modo de compatibilidade de 2008.
Você diz que o UPDATE está rodando em loop e ainda estava rodando depois de 2,5 horas. Esse loop atualizou alguma linha? Era o próprio loop que estava demorando muito ou uma única instrução UPDATE? Essa é uma distinção um tanto importante e atualmente é ambígua nas informações fornecidas. No entanto, aqui estão algumas coisas a serem observadas com base nas coisas ditas na pergunta:
Não, o SQL Server não deve atualizar índices que não usam a nova coluna
Desativar índices não é simplesmente uma questão de desativá-los. Na verdade, ele descarta todas as páginas de índice e mantém apenas a estrutura para que você não precise executar a instrução CREATE completa novamente. Mas reabilitar um índice terá que reconstruí-lo.
E aqui estão algumas coisas para procurar:
Há algum gatilho UPDATE na
Child
tabela?Qual é a configuração de crescimento automático no log de transações? Se definido como um número muito baixo, pode ser que os UPDATEs sejam impedidos por um grande número de operações de crescimento automático.
Desses 5 índices na
Child
tabela, algum deles temFKId
como coluna inicial?Você já tentou tamanhos de lote menores ou apenas 20k? Já vi várias pessoas recomendarem aleatoriamente tamanhos de lote grandes (10k - 50k) para esses tipos de operações sem considerar que isso não apenas limita a operação a esse número, mas também sugere ao Otimizador de consultas que o número é possível de ser atingido em o primeiro lugar. Portanto, se houver apenas 5.000 linhas para localizar, ele poderá continuar examinando-as para ver se outras atendem aos
c.NewColumn IS NULL
critérios. E considerando que o campo não está indexado, tudo o que o QO tem que continuar são as estatísticas geradas automaticamente que não informam onde encontrar o restanteNULL
linhas. Presumindo que as primeiras iterações do loop foram bem-sucedidas, o SQL Server ainda precisa localizar 20.000 linhas NULL, dos 6,5 milhões, verificando quantas forem necessárias, em nenhuma ordem específica, antes de localizá-las. Portanto, as primeiras iterações provavelmente ocorreram rapidamente, mas esse tipo de operação diminui rapidamente, pois cada passagem sucessiva precisa verificar mais e mais registros antes de encontrar os 20.000 que atendem aosIS NULL
critérios.Então, duas coisas a considerar:
Em vez de se livrar dos índices, você pode querer criar um índice, temporariamente, para dar suporte a essa operação UPDATE específica. Um índice filtrado (que foi introduzido no SQL Server 2008 para que o modo de compatibilidade não seja um problema) permitirá que você direcione as linhas restantes para atualização. Algo como:
Tinha me esquecido dessa pergunta, desculpe. Mas resolvemos o problema. O uso de uma instrução MERGE reduziu o tempo de consulta para menos de uma hora. A desativação de índices não teve efeito.