Tanto quanto posso dizer, você pode otimizar uma inserção em massa de uma maneira muito semelhante à de uma inserção regular. Normalmente, um plano de consulta para uma inserção simples não é muito informativo; portanto, não se preocupe em não ter o plano. Analisarei algumas maneiras de otimizar uma inserção, mas a maioria delas provavelmente não se aplica à inserção especificada na pergunta. No entanto, eles podem ser úteis se, no futuro, você precisar carregar grandes quantidades de dados.
1. Insira os dados na ordem das chaves de cluster
O SQL Server geralmente classifica os dados antes de inseri-los em uma tabela com um índice clusterizado. Para algumas tabelas e aplicativos, você pode melhorar o desempenho classificando os dados no arquivo simples e informando o SQL Server que os dados são classificados pelo ORDER
argumento de BULK INSERT
:
PEDIDO ({coluna [ASC | DESC]} [, ... n])
Especifica como os dados no arquivo de dados são classificados. O desempenho da importação em massa é aprimorado se os dados que estão sendo importados forem classificados de acordo com o índice em cluster da tabela, se houver.
Como você está usando uma IDENTITY
coluna como chave em cluster, não precisa se preocupar com isso.
2. Use TABLOCK
se possível
Se você tiver apenas uma sessão inserindo dados em sua tabela, poderá especificar o TABLOCK
argumento para BULK INSERT
. Isso pode reduzir a contenção de bloqueio e pode levar ao registro mínimo em alguns cenários. No entanto, você está inserindo em uma tabela com um índice clusterizado que já contém dados, para que você não obtenha log mínimo sem o sinalizador de rastreamento 610, mencionado posteriormente nesta resposta.
Se TABLOCK
não for possível, porque você não pode alterar o código , nem toda a esperança se perde. Considere usar sp_table_option
:
EXEC [sys].[sp_tableoption]
@TableNamePattern = N'dbo.BulkLoadTable' ,
@OptionName = 'table lock on bulk load' ,
@OptionValue = 'ON'
Outra opção é ativar o sinalizador de rastreamento 715 .
3. Use um tamanho de lote apropriado
Às vezes, você poderá ajustar as inserções alterando o tamanho do lote.
ROWS_PER_BATCH = linhas_per_batch
Indica o número aproximado de linhas de dados no arquivo de dados.
Por padrão, todos os dados no arquivo de dados são enviados ao servidor como uma única transação, e o número de linhas no lote é desconhecido para o otimizador de consulta. Se você especificar ROWS_PER_BATCH (com um valor> 0), o servidor utilizará esse valor para otimizar a operação de importação em massa. O valor especificado para ROWS_PER_BATCH deve ser aproximadamente o mesmo que o número real de linhas. Para obter informações sobre considerações de desempenho, consulte "Comentários", posteriormente neste tópico.
Aqui está a citação de mais adiante neste artigo:
Se o número de páginas a serem liberadas em um único lote exceder um limite interno, poderá ocorrer uma varredura completa do buffer pool para identificar quais páginas serão liberadas quando o lote for confirmado. Essa verificação completa pode prejudicar o desempenho da importação em massa. Um provável caso de exceder o limite interno ocorre quando um buffer pool grande é combinado com um subsistema de E / S lento. Para evitar estouros de buffer em máquinas grandes, não use a dica TABLOCK (que removerá as otimizações em massa) ou use um tamanho de lote menor (que preserva as otimizações em massa).
Como os computadores variam, recomendamos que você teste vários tamanhos de lote com a carga de dados para descobrir o que funciona melhor para você.
Pessoalmente, eu insira todas as 695 linhas em um único lote. O ajuste do tamanho do lote pode fazer uma grande diferença ao inserir muitos dados.
4. Verifique se você precisa da IDENTITY
coluna
Não sei nada sobre seu modelo ou requisitos de dados, mas não caia na armadilha de adicionar uma IDENTITY
coluna a todas as tabelas. Aaron Bertrand tem um artigo sobre isso chamado Maus hábitos: colocar uma coluna de IDENTIDADE em todas as tabelas . Para ficar claro, não estou dizendo que você deve remover a IDENTITY
coluna desta tabela. No entanto, se você determinar que a IDENTITY
coluna não é necessária e removê-la, isso poderá melhorar o desempenho da pastilha.
5. Desative índices ou restrições
Se você estiver carregando uma grande quantidade de dados em uma tabela em comparação com o que você já possui, pode ser mais rápido desativar índices ou restrições antes do carregamento e ativá-los após o carregamento. Para grandes quantidades de dados, geralmente é mais ineficiente para o SQL Server criar um índice de uma só vez, em vez de os dados serem carregados na tabela. Parece que você inseriu 695 linhas em uma tabela com 11500 linhas, portanto, eu não recomendaria essa técnica.
6. Considere TF 610
O Trace Flag 610 permite o registro mínimo em alguns cenários adicionais. Para sua tabela com uma IDENTITY
chave em cluster, você obteria um registro mínimo para novas páginas de dados, desde que seu modelo de recuperação seja simples ou com registro em massa. Acredito que esse recurso não esteja ativado por padrão, pois pode prejudicar o desempenho em alguns sistemas. Você precisaria testar cuidadosamente antes de ativar esse sinalizador de rastreamento. A referência recomendada da Microsoft ainda parece ser The Data Loading Performance Guide
Impacto de E / S do registro mínimo sob sinalizador de rastreamento 610
Quando você confirma uma transação de carregamento em massa que foi minimamente registrada, todas as páginas carregadas devem ser liberadas para o disco antes que a confirmação seja concluída. Quaisquer páginas liberadas não capturadas por uma operação anterior do ponto de verificação podem criar uma grande quantidade de E / S aleatória. Compare isso com uma operação totalmente registrada, que cria E / S sequenciais nas gravações de log e não exige que as páginas carregadas sejam liberadas para o disco no momento da confirmação.
Se o seu cenário de carregamento for pequenas operações de inserção em árvores que não cruzam os limites do ponto de verificação e você tiver um sistema de E / S lento, o uso de log mínimo poderá realmente diminuir a velocidade da inserção.
Até onde eu sei, isso não tem nada a ver com o sinalizador de rastreamento 610, mas com o mínimo de registro em si. Acredito que a citação anterior sobre o ROWS_PER_BATCH
ajuste estava chegando ao mesmo conceito.
Em conclusão, provavelmente não há muito que você possa fazer para ajustar o seu BULK INSERT
. Eu não ficaria preocupado com a contagem de leituras que você observou com sua inserção. O SQL Server relatará leituras sempre que você inserir dados. Considere o seguinte muito simples INSERT
:
DROP TABLE IF EXISTS X_TABLE;
CREATE TABLE X_TABLE (
VAL VARCHAR(1000) NOT NULL
);
SET STATISTICS IO, TIME ON;
INSERT INTO X_TABLE WITH (TABLOCK)
SELECT REPLICATE('Z', 1000)
FROM dbo.GetNums(10000); -- generate 10000 rows
Saída de SET STATISTICS IO, TIME ON
:
Tabela 'X_TABLE'. Contagem de varreduras 0, leituras lógicas 11428
Eu tenho 11428 leituras relatadas, mas isso não é uma informação acionável. Às vezes, o número de leituras relatadas pode ser reduzido com o mínimo de log, mas é claro que a diferença não pode ser traduzida diretamente em um ganho de desempenho.