Como posso adicionar uma coluna de versão de linha a uma tabela grande com tempo de inatividade mínimo

21

Usando o SQL Server 2008 e posterior, desejo adicionar uma coluna de versão de linha a uma tabela grande, no entanto, quando simplesmente

ALTER TABLE [Tablename]
ADD Rowversion [Rowversion] NOT NULL

Em seguida, a tabela fica indisponível para atualizações por muito tempo.

Quais estratégias posso usar para reduzir esse tempo de inatividade? Vou considerar qualquer coisa. Quanto mais simples, melhor, é claro, mas vou considerar qualquer estratégia.

Meu pensamento é que, como último recurso, eu poderia manter uma tabela de armazenamento temporário de cópia mantida por gatilhos e depois sp_rename a tabela de armazenamento temporário na tabela original. Mas espero algo mais simples / fácil.

Michael J Swart
fonte

Respostas:

26

Considere criar uma nova tabela com o mesmo esquema mais a coluna rowversion e adicione uma visualização no topo das duas tabelas que faz a união de todas. Peça às pessoas que usem a visualização e escrevam, em vez de gatilhos, nas tabelas e visualizações subjacentes.

As inserções devem ser enviadas para a nova tabela, as atualizações devem mover os dados para a nova tabela e as exclusões devem ser aplicadas a ambas as tabelas.

Em seguida, faça movimentos em lote em segundo plano, movendo o maior número possível de registros por vez para a nova tabela. Você ainda pode ter problemas de simultaneidade enquanto isso ocorre e alguns planos de execução impressionantes, mas permite que você fique on-line enquanto as mudanças estão acontecendo.

Idealmente, você inicia o processo na sexta-feira à tarde para minimizar o efeito nos usuários finais e tenta fazê-lo antes da segunda-feira de manhã. Uma vez instalado, você pode alterar a exibição para apontar apenas para a nova tabela, e os planos de execução mais importantes desaparecem. Idealmente.

Para evitar que os gatilhos sejam disparados quando os dados estão sendo migrados em lotes, observe o número de linhas nas tabelas excluídas / inseridas no gatilho e pule as atividades se elas estiverem próximas ao número de linhas no seu lote.


No final, Michael decidiu pular a exibição (e não excluir da tabela original) para obter planos mais estáveis. A troca estava segurando essencialmente duas cópias da mesa. Ele transformou em uma série de postagens no blog .

Brent Ozar
fonte
7

Se você tiver tempo para planejar com antecedência, há uma solução muito mais fácil ... (geralmente)

Os bloqueios longos são quase certamente causados ​​por divisões de página na camada de armazenamento. Então, force-os em seu próprio horário.

  1. Adicionar uma coluna temporária compatível com NULL com tipo de dados VARBINARY(8) .
  2. Localize o tempo de folga disponível no banco de dados para atualizar lotes dos registros existentes com um valor válido para o campo. (0x0000000027F95A5B por exemplo)
  3. As atualizações forçarão as divisões de página necessárias e alocarão mais espaço para a tabela.
  4. Quando estiver em dia, solte a coluna temporária (não toca no armazenamento alocado) e adicione a coluna versão de linha.
  5. Nenhuma página é dividida e um bloqueio é necessário apenas o tempo suficiente para preencher os valores.

Eu usei isso com sucesso para adicionar uma coluna de versão de linha a uma tabela de linha de 150 milhões em menos de 10 minutos.

Advertência ... se você possui uma tabela com grandes campos varchar (especialmente varchar(max)), o SQL Server decide reconstruir a tabela em vez de reutilizar o novo espaço disponível. Ainda tentando descobrir uma maneira de contornar isso.

Scott Lynch
fonte
Interessante, acho que não especifiquei o que "muito tempo" significava na minha pergunta. Se> 30 minutos for muito longo para o seu cenário e 10 minutos forem toleráveis, esta solução funcionaria. Meu cenário envolveu tentar atingir zero tempo de inatividade ou mais especificamente <10 segundos, o que é alcançado pela resposta de Brent.
Michael J Swart
1

Se TIMESTAMPvocê está adicionando é NULLABLE:

  1. Adicione uma VARBINARY(8)coluna
  2. Preencher com dados.

Depois de preenchida, nas instruções SQL de volta para trás, DROPa VARBINARY(8)coluna que você acabou de adicionar e preencher e adicione a TIMESTAMP NULLcoluna.


Se TIMESTAMPvocê está adicionando é NOT NULLABLE:

  1. Adicione uma BINARY(8)coluna
  2. Preencher com dados.

Depois de preenchida, nas instruções SQL de back-to-back, DROPa BINARY(8)coluna que você acabou de adicionar e preencheu e ADD THE TIMESTAMP NOT NULLcolumn.

Paul White diz que a GoFundMonica
fonte