Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Maneira mais rápida de atualizar 120 milhões de registros


A única maneira sensata de atualizar uma tabela de 120 milhões de registros é com um SELECT declaração que preenche um segundo tabela. Você tem que tomar cuidado ao fazer isso. Instruções abaixo.

Caso Simples

Para uma tabela sem um índice clusterizado, durante um tempo sem DML simultâneo:
  • SELECT *, new_col = 1 INTO clone.BaseTable FROM dbo.BaseTable
  • recriar índices, restrições, etc. na nova tabela
  • trocar antigo e novo com ALTER SCHEMA ... TRANSFER.
  • soltar tabela antiga

Se você não puder criar um esquema clone, um nome de tabela diferente no mesmo esquema servirá. Lembre-se de renomear todas as suas restrições e gatilhos (se aplicável) após a troca.

Caso não simples

Primeiro, recrie sua BaseTable com o mesmo nome em um esquema diferente, por exemplo, clone.BaseTable . Usar um esquema separado simplificará o processo de renomeação posteriormente.
  • Incluir o índice clusterizado , se aplicável. Lembre-se de que chaves primárias e restrições exclusivas podem ser agrupadas, mas não necessariamente.
  • Incluir colunas de identidade e colunas computadas , se aplicável.
  • Inclua sua nova coluna INT , onde quer que pertença.
  • Não incluir qualquer um dos seguintes:
    • gatilhos
    • restrições de chave estrangeira
    • índices não clusterizados/chaves primárias/restrições exclusivas
    • verifique as restrições ou restrições padrão. Os padrões não fazem muita diferença, mas estamos tentando manter o mínimo.

Em seguida, teste sua inserção com 1000 linhas:
-- assuming an IDENTITY column in BaseTable
SET IDENTITY_INSERT clone.BaseTable ON
GO
INSERT clone.BaseTable WITH (TABLOCK) (Col1, Col2, Col3)
SELECT TOP 1000 Col1, Col2, Col3 = -1
FROM dbo.BaseTable
GO
SET IDENTITY_INSERT clone.BaseTable OFF

Examine os resultados. Se tudo aparecer em ordem:
  • truncar a tabela clone
  • certifique-se de que o banco de dados esteja no modelo bulk-logged ou de recuperação simples
  • faça a inserção completa.

Isso vai demorar um pouco, mas não tanto quanto uma atualização. Depois de concluído, verifique os dados na tabela de clones para garantir que tudo esteja correto.

Em seguida, recrie todas as chaves primárias/restrições/índices exclusivos não clusterizados e restrições de chave estrangeira (nessa ordem). Recrie o padrão e verifique as restrições, se aplicável. Recrie todos os gatilhos. Recrie cada restrição, índice ou gatilho em um lote separado. por exemplo:
ALTER TABLE clone.BaseTable ADD CONSTRAINT UQ_BaseTable UNIQUE (Col2)
GO
-- next constraint/index/trigger definition here

Por fim, mova dbo.BaseTable para um esquema de backup e clone.BaseTable para o esquema dbo (ou onde quer que sua tabela fique).
-- -- perform first true-up operation here, if necessary
-- EXEC clone.BaseTable_TrueUp
-- GO
-- -- create a backup schema, if necessary
-- CREATE SCHEMA backup_20100914
-- GO
BEGIN TRY
  BEGIN TRANSACTION
  ALTER SCHEMA backup_20100914 TRANSFER dbo.BaseTable
  -- -- perform second true-up operation here, if necessary
  -- EXEC clone.BaseTable_TrueUp
  ALTER SCHEMA dbo TRANSFER clone.BaseTable
  COMMIT TRANSACTION
END TRY
BEGIN CATCH
  SELECT ERROR_MESSAGE() -- add more info here if necessary
  ROLLBACK TRANSACTION
END CATCH
GO

Se você precisar liberar espaço em disco, poderá descartar sua tabela original neste momento, embora possa ser prudente mantê-la por mais algum tempo.

Escusado será dizer que este é idealmente um offline Operação. Se você tiver pessoas modificando dados enquanto executa essa operação, terá que realizar uma operação de alinhamento com a opção de esquema. Eu recomendo criar um gatilho em dbo.BaseTable para registrar todos os DML em uma tabela separada. Habilite este acionador antes de iniciar a inserção. Em seguida, na mesma transação em que você executa a transferência de esquema, use a tabela de log para realizar um alinhamento. Teste isso primeiro em um subconjunto dos dados! Deltas são fáceis de estragar.