Como as outras respostas já indicam, o SQL Server pode ou não garantir explicitamente que as linhas sejam classificadas em ordem de índice em cluster antes da insert
.
Isso depende se o operador de índice clusterizado no plano tem ou não a DMLRequestSort
propriedade configurada (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, poderá se beneficiar da adição de um explícito ORDER BY
à SELECT
consulta para minimizar as divisões de páginas e a fragmentação resultante da INSERT
operação
Exemplo:
use tempdb;
GO
CREATE TABLE T(N INT PRIMARY KEY,Filler char(2000))
CREATE TABLE T2(N INT PRIMARY KEY,Filler char(2000))
GO
DECLARE @T TABLE (U UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),N int)
INSERT INTO @T(N)
SELECT number
FROM master..spt_values
WHERE type = 'P' AND number BETWEEN 0 AND 499
/*Estimated row count wrong as inserting from table variable*/
INSERT INTO T(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
/*Same operation using explicit sort*/
INSERT INTO T2(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
ORDER BY T1.N*1000 + T2.N
SELECT avg_fragmentation_in_percent,
fragment_count,
page_count,
avg_page_space_used_in_percent,
record_count
FROM sys.dm_db_index_physical_stats(2, OBJECT_ID('T'), NULL, NULL, 'DETAILED')
;
SELECT avg_fragmentation_in_percent,
fragment_count,
page_count,
avg_page_space_used_in_percent,
record_count
FROM sys.dm_db_index_physical_stats(2, OBJECT_ID('T2'), NULL, NULL, 'DETAILED')
;
Mostra que T
está massivamente fragmentado
avg_fragmentation_in_percent fragment_count page_count avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
99.3116118225536 92535 92535 67.1668272794663 250000
99.5 200 200 74.2868173956017 92535
0 1 1 32.0978502594514 200
Mas a T2
fragmentação é mínima
avg_fragmentation_in_percent fragment_count page_count avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
0.376 262 62500 99.456387447492 250000
2.1551724137931 232 232 43.2438349394613 62500
0 1 1 37.2374598468001 232
Por outro lado, às vezes você pode 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 em cluster. 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 por
DECLARE @var INT =2147483647
INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar
O SQL Server estimará que 100 linhas serão inseridas, independentemente do tamanho Bar
abaixo do limite no qual uma classificação é adicionada ao plano. No entanto, conforme apontado nos comentários abaixo, isso significa que a inserção infelizmente não poderá tirar proveito do registro mínimo.
Se o otimizador decidir que seria mais eficiente classificar os dados antes da inserção, 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 omitir isso novamente. Observe que o plano de execução escolhido pode variar de execução para execução, dependendo do número de linhas inseridas na sua tabela de preparação.
Se você pode capturar planos de execução do processo com e sem a classificação explícita, anexe-os à sua pergunta para comentar.
Edit: 2011-10-28 17:00
A resposta do @ Gonsalu parece mostrar que sempre ocorre uma operação de classificação, não é esse o caso. Scripts de demonstração necessários!
Como os scripts estavam ficando muito grandes, eu os mudei para o 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 iguais, nenhuma classificação ocorre em qualquer lugar do plano e a verificação de índice em cluster é "ordenada = falsa".
Segunda execução, inserindo 26 linhas.
Desta vez, os planos diferem.
Portanto, há um ponto de inflexão em que o otimizador considera uma classificação necessária. Como o @MartinSmith mostra, isso parece se basear nas linhas estimadas a serem inseridas. No meu equipamento de teste, 25 não exige classificação, 26 requer (2K5SP3, núcleo duplo, 8 GB)
O script SQLCMD inclui variáveis que permitem alterar o tamanho das linhas da tabela (alterando a densidade da página) e o número de linhas no dbo.MyTable antes das inserções adicionais. Dos meus testes, nenhum deles afeta o ponto de inflexão.
Se algum leitor desejar, execute os scripts e adicione seu ponto de inflexão como um comentário. Interessado em saber se isso varia entre plataformas de teste e / ou versões.
Edit: 2011-10-28 20:15
Testes repetidos no mesmo equipamento, mas com 2K8R2. Desta vez, o ponto de inflexão é 251 linhas. Mais uma vez, variar a densidade da página e as contagens de linhas existentes não tem efeito.
fonte
A
ORDER BY
cláusula naSELECT
declaração é redundante.É redundante porque as linhas que serão inseridas, se precisarem ser classificadas , são classificadas de qualquer maneira.
Vamos criar um caso de teste.
Vamos ativar 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
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áusulaO 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áusulaAgora, 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, porque, mesmo com uma explícitaORDER 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 registro mínimoINSERT
, mas isso está fora do escopo desta pergunta.Atualizado em 11/11/2011: como Mark Smith mostrou , os
INSERT
s em uma tabela com um índice clusterizado nem sempre precisam ser classificados - aORDER BY
cláusula também é redundante nesse caso.fonte