Incluindo colunas nas tabelas de produção

28

Qual é a melhor maneira de adicionar colunas a grandes tabelas de produção no SQL Server 2008 R2? De acordo com os livros online da Microsoft:

As alterações especificadas em ALTER TABLE são implementadas imediatamente. Se as alterações exigirem modificações nas linhas da tabela, ALTER TABLE atualizará as linhas. ALTER TABLE adquire um bloqueio de modificação de esquema na tabela para garantir que nenhuma outra conexão faça referência aos metadados da tabela durante a alteração, exceto as operações de índice online que exigem um bloqueio SCH-M muito curto no final.

(http://msdn.microsoft.com/en-us/library/ms190273.aspx)

Em uma tabela grande com milhões de linhas, isso pode demorar um pouco. Tomar uma interrupção é a única opção? Qual é a melhor maneira de lidar com esse tipo de situação?

sh-beta
fonte
1
Artigo recente sobre esse problema: sqlservercentral.com/articles/Change+Tracking/74397
8kb

Respostas:

27

"Depende"

Se você adicionar uma coluna que não exija adição de dados às linhas, poderá ser bastante rápida.

Por exemplo, adicionar um int ou char requer movimentos físicos de linha. A adição de um varchar anulável sem padrão não deve (a menos que o bitmap NULL precise ser expandido)

Você precisa experimentá-lo em uma cópia restaurada da produção para obter uma estimativa

Criar uma nova tabela, copiar, renomear pode levar mais tempo se você precisar adicionar novamente índices e chaves em uma tabela de bilhões de linhas.

Alterei bilhões de tabelas de linhas que levaram alguns segundos para adicionar uma coluna anulável.

Eu disse para fazer um backup primeiro?

gbn
fonte
2
+1 no backup. e verifique se você também tem espaço de log suficiente.
SqlACID
Você pode esclarecer por que adicionar um int ou char requer movimentos físicos de linha?
sh-beta
5
Você quis dizer "não" exige a adição de dados às linhas da sua segunda linha?
21812 Ben Brocka
21

Se a coluna for NULLable, o impacto deve ser insignificante. Se a coluna não puder ser NULL e o valor precisar ser definido, poderá ser bem diferente. O que eu faria neste caso é, em vez de adicionar uma restrição não nula e padrão de uma só vez, efetivamente adicionando dados a cada linha:

  • adicione a coluna como NULLable - deve ser rápido na maioria dos casos
  • atualize os valores para o padrão
    • você pode fazer isso em lotes, se necessário
    • você também pode usar isso para aplicar lógica condicional em que algumas linhas podem não obter o padrão
  • adicione as restrições não nulas / padrão
    • isso será mais rápido quando nenhum dos dados for NULL, mas ainda deve ser mensurável

Concorde com o @gbn que você pode testar isso restaurando uma cópia da produção e testando lá ... você terá uma boa idéia do tempo (assumindo que o hardware é um pouco semelhante) e também poderá ver o impacto no log de transações.

Aaron Bertrand
fonte
Quanto ao último bit: •add the not null/default constraintsnão tenho certeza de que não há um problema em potencial com isso ... Quando o MSSQL (mesmo 2008R2) altera uma coluna não nula para nula, se você colocar um rastreio, poderá vê-lo realmente debaixo das cobertas fazendo uma atualização completa de todas as linhas da tabela, ou seja update table1 set column1 = column1, presumo que esteja fazendo a verificação não nula de uma maneira completamente idiota. Essa transação é duas vezes o tamanho da tabela (páginas anteriores e posteriores), portanto, para uma tabela DW pode ser enorme. Anteriormente tivemos de dados bcp fora, truncado, não nulo para a mudança não nulo, então BCP no.
Se alguém conhece uma maneira de contornar isso, eu adoro saber ... Em contraste, no Oracle, alterar nulo para não nulo trava, depois seleciona-se para verificar se não há nulos e, em seguida, uma atualização instantânea puramente de metadados.
Hey @ Mike, isso soa como uma boa pergunta em potencial.
Derek Downey
4

Você considerou:

  1. Criando uma nova tabela que inclui as alterações na definição da tabela.
  2. Inserindo na nova definição de tabela, selecionando na tabela original.
  3. Renomeando a tabela original para _orig e renomeando a nova tabela para o nome da tabela original.

A desvantagem aqui é que você precisa ter espaço suficiente no banco de dados para fazer essa alteração. Você ainda pode precisar de um bloqueio de leitura na mesa para evitar leituras sujas.

No entanto, você minimiza o impacto para os usuários finais, se houver uma chance ou necessidade de acessar a tabela original simultaneamente. Também deve minimizar as durações do bloqueio.

RobPaller
fonte
Você não precisaria de um bloqueio de gravação , em vez de ler? É bom que os usuários vejam dados na tabela antiga, você simplesmente não quer que eles confirmem alterações que seriam substituídas quando você concluir a troca de buffer.
Jon of All Trades
Esse foi o meu pensamento com meu chapéu de data warehouse sobre onde as mudanças podem ser controladas um pouco mais fácil. Em uma situação OLTP correta, um bloqueio de gravação seria necessário para evitar alterações na tabela.
RobPaller