Eu tenho uma instrução SQL que insere linhas em uma tabela com um índice clusterizado na coluna TRACKING_NUMBER.
POR EXEMPLO:
INSERT INTO TABL_NAME (TRACKING_NUMBER, COLB, COLC)
SELECT TRACKING_NUMBER, COL_B, COL_C
FROM STAGING_TABLE
Minha pergunta é - ajuda usar uma cláusula ORDER BY na instrução SELECT para a coluna de índice clusterizado ou qualquer ganho obtido seria negado pela classificação extra necessária para a cláusula ORDER BY?
Como as outras respostas já indicam, o SQL Server pode ou não garantir explicitamente que as linhas sejam classificadas na ordem do índice clusterizado antes do
insert
.Isso depende se o operador de índice clusterizado no plano tem ou não a
DMLRequestSort
propriedade definida (que, por sua vez, depende do número estimado de linhas inseridas).Se você achar que o SQL Server está subestimando isso por qualquer motivo, você pode se beneficiar da adição de um explícito
ORDER BY
àSELECT
consulta para minimizar as divisões de página e a fragmentação resultante daINSERT
operaçãoExemplo:
Mostra que
T
é massivamente fragmentadaMas para a
T2
fragmentação é mínimaPor outro lado, às vezes você pode querer forçar o SQL Server a subestimar a contagem de linhas quando você sabe que os dados já estão pré-classificados e deseja evitar uma classificação desnecessária. Um exemplo notável é ao inserir um grande número de linhas em uma tabela com uma
newsequentialid
chave de índice clusterizado. Nas versões do SQL Server anteriores ao Denali, o SQL Server adiciona uma operação de classificação desnecessária e potencialmente cara . Isso pode ser evitado porO SQL Server estimará que 100 linhas serão inseridas, independentemente do tamanho
Bar
que estiver abaixo do limite no qual uma classificação é adicionada ao plano. No entanto, como apontado nos comentários abaixo, isso significa que a inserção infelizmente não poderá aproveitar o registro mínimo.Se o otimizador decidir que seria mais eficiente classificar os dados antes da inserção, ele o fará em algum lugar a montante do operador de inserção. Se você introduzir uma classificação como parte de sua consulta, o otimizador deverá perceber que os dados já estão classificados e deixar de fazê-lo novamente. Observe que o plano de execução escolhido pode variar de execução para execução, dependendo do número de linhas inseridas em sua tabela de preparo.
Se você puder capturar os planos de execução do processo com e sem a classificação explícita, anexe-os à sua pergunta para comentário.
Editar: 28/10/2011 17:00
A resposta do @Gonsalu parece mostrar que uma operação de classificação sempre ocorre, esse não é o caso. Scripts de demonstração necessários!
Como os scripts estavam ficando muito grandes, eu os movi para Gist . Para facilitar a experimentação, os scripts usam o modo SQLCMD. Os testes são executados em 2K5SP3, dual core, 8GB.
Os testes de inserção abrangem três cenários:
Primeira execução, inserindo 25 linhas.
Todos os três planos de execução são os mesmos, nenhuma classificação ocorre em nenhum lugar do plano e a varredura de índice clusterizado é "ordered=false".
Segunda execução, inserindo 26 linhas.
Desta vez os planos são diferentes.
Portanto, há um ponto de inflexão em que o otimizador considera necessária uma classificação. Como mostra @MartinSmith, isso parece ser baseado nas linhas estimadas a serem inseridas. No meu equipamento de teste 25 não requer uma classificação, 26 sim (2K5SP3, dual core, 8GB)
O script SQLCMD inclui variáveis que permitem alterar o tamanho das linhas na tabela (alterando a densidade da página) e o número de linhas em dbo.MyTable antes das inserções adicionais. Dos meus testes, nenhum deles tem qualquer efeito sobre o ponto de inflexão.
Se algum leitor estiver tão inclinado, por favor, execute os scripts e adicione seu ponto de inflexão como um comentário. Interessado em saber se varia entre as plataformas de teste e/ou versões.
Editar: 28/10/2011 20:15
Testes repetidos no mesmo equipamento, mas com 2K8R2. Desta vez, o ponto de inflexão é de 251 linhas. Novamente, variar a densidade da página e as contagens de linhas existentes não tem efeito.
A
ORDER BY
cláusula naSELECT
declaração é redundante.É redundante porque as linhas que serão inseridas, caso precisem ser classificadas , serão classificadas de qualquer maneira.
Vamos criar um caso de teste.
Vamos habilitar a exibição de texto dos planos de consulta reais, para que possamos ver quais tarefas são executadas pelo processador de consultas.
Agora, vamos
INSERT
inserir 2K linhas na tabela sem umaORDER BY
cláusula.O plano de execução real para esta consulta é o seguinte.
Como você pode ver, há um operador Sort antes que o INSERT real ocorra.
Agora, vamos limpar a tabela e
INSERT
2k linhas na tabela com aORDER BY
cláusula.O plano de execução real para esta consulta é o seguinte.
Observe que é o mesmo plano de execução usado para a
INSERT
instrução sem aORDER BY
cláusula.Agora, a
Sort
operação nem sempre é necessária, como Mark Smith mostrou em outra resposta (se o número de linhas a serem inseridas for baixo), mas aORDER BY
cláusula ainda é redundante nesse caso, pois mesmo com um explicitORDER BY
, nenhumaSort
operação é gerada pelo processador de consultas.Você pode otimizar uma
INSERT
instrução em uma tabela com um índice clusterizado usando um minimamente logadoINSERT
, mas isso está fora do escopo desta pergunta.Atualizado em 2011-11-02: Como Mark Smith mostrou ,
INSERT
s em uma tabela com um índice clusterizado nem sempre precisa ser classificado - aORDER BY
cláusula também é redundante nesse caso.