Qual é a maneira mais rápida de inserir um grande número de linhas?

27

Eu tenho um banco de dados onde eu carrego arquivos em uma tabela intermediária; dessa tabela intermediária, eu tenho 1-2 associações para resolver algumas chaves estrangeiras e, em seguida, insiro essas linhas na tabela final (que possui uma partição por mês). Eu tenho cerca de 3,4 bilhões de linhas para três meses de dados.

Qual é a maneira mais rápida de obter essas linhas de teste para a mesa final? Tarefa de fluxo de dados do SSIS (que usa uma exibição como fonte e possui carregamento rápido ativo) ou um comando Inserir INTO SELECT ....? Tentei a tarefa de fluxo de dados e posso obter cerca de 1 bilhão de linhas em cerca de 5 horas (8 núcleos / 192 GB de RAM no servidor), o que me parece muito lento.

nojetlag
fonte
11
As partições estão em grupos de arquivos separados (e nesses grupos em diferentes discos físicos)?
Aaron Bertrand
3
Um recurso realmente bom O Guia de Desempenho para Carregamento de Dados . Isso aborda muitas otimizações de desempenho que você pode fazer, por exemplo, habilitando o TF610 , usando BCP OUT / IN, SSIS etc. Você só precisa seguir as recomendações e testá-las em seu ambiente.
Kin Shah
@ Aaron sim, por mês um grupo de arquivos, 12 san lun anexados para que todos os jan passem um lun etc. Não se sabe quantos discos por lun, mas deve ser suficiente.
nojetlag
Sim, eu realmente quis dizer "conjuntos de discos" e provavelmente também poderia ter mencionado os controladores, que podem ficar saturados.
Aaron Bertrand
O @Kin deu uma olhada no guia, mas parece desatualizado: "O destino do SQL Server é a maneira mais rápida de carregar em massa dados de um fluxo de dados do Integration Services para o SQL Server. Esse destino oferece suporte a todas as opções de carregamento em massa do SQL Server - exceto ROWS_PER_BATCH . " e no SSIS 2012, eles recomendam o destino do OLE DB para obter melhor desempenho.
nojetlag

Respostas:

25

Uma abordagem comum:

  1. Desative / descarte índices / restrições na tabela de destino.
  2. INSERT dbo.[Target] WITH (TABLOCKX) SELECT ...
  3. Obviamente, com crédito ao JNK, você pode fazer o acima em lotes de nlinhas, o que pode reduzir a tensão no log de transações e, é claro, significa que, se algum lote falhar, você só precisará iniciar a partir desse lote. Eu publiquei um blog sobre isso (enquanto em referência a exclusões, os mesmos conceitos básicos se aplicam) aqui: http://www.sqlperformance.com/2013/03/io-subsystem/chunk-deletes
  4. Reative / recrie índices / restrições na tabela de destino (e talvez você possa adiar alguns deles, se não forem necessários para todas as operações, e é mais importante disponibilizar os dados básicos rapidamente).

Se suas partições são físicas e não apenas lógicas, você pode ganhar algum tempo fazendo com que processos diferentes preencham partições diferentes simultaneamente (é claro que isso significa que você não pode usar TABLOCK/ TABLOCKX). Isso pressupõe que a fonte também seja adequada para vários processos, selecionando sem sobreposição / bloqueio etc., e tornando esse lado da operação ainda mais lento (dica: crie um índice em cluster na fonte que se adapte ao esquema de particionamento no destino).

Você também pode considerar algo muito mais primitivo, como BCP OUT/BCP IN .

Não sei se eu pularia para o SSIS para ajudar com isso. Provavelmente existem algumas eficiências por lá, mas não sei se o esforço justifica a economia.

Aaron Bertrand
fonte
2
Não descarte índices cegamente (especialmente o índice clusterizado) se seus dados não estiverem classificados. Eliminar o índice e esperar recriar um índice em cluster pode ser um grande erro, pois pode custar muito espaço em disco e grande quantidade de tempo. Eu não sou o primeiro a experimentar esse erro. Veja a descrição do "Plano B" neste artigo sqlmag.com/t-sql/… . O autor teve o mesmo problema.
jyao
10

Olhando para o seu problema da perspectiva do SSIS, sinto que a razão pela qual isso pode levar tanto tempo é que você não utilizou o lote. Isso pode levar a muitas linhas preenchendo o pipeline do SSIS e, consequentemente, prejudicar o desempenho do SSIS. O que você precisa fazer é alterar as configurações de linhas por lote e, possivelmente, o tamanho máximo de confirmação da inserção. Agora, o que você definiu também dependerá da quantidade de memória disponível para o servidor SSIS? Qual é a velocidade do disco da sua instância do SQL Server? A melhor maneira de fazer isso é testar. Vamos, por exemplo, usar 10.000. Isso enviará um lote para o servidor 10.000 de cada vez, evitando que o pipeline seja sobrecarregado e ajudará a executar esse processo mais rapidamente. Essas configurações são definidas no seu destino OLEDB.

Destino OLEDB

Se for um problema, você também poderá adicionar uma tarefa de execução SQL antes e depois, conforme o @AaronBertrand sugere e remover / re adicionar quaisquer índices ou restrições à tabela.

Zane
fonte
11
Há uma excelente pergunta sobre o que "carregamento rápido" implica em outro lugar no DBA.SE: dba.stackexchange.com/questions/141430/… .
Jon of All Trades