Dado o próximo exemplo:
IF OBJECT_ID('dbo.my_table') IS NOT NULL
DROP TABLE [dbo].[my_table];
GO
CREATE TABLE [dbo].[my_table]
(
[id] int IDENTITY (1,1) NOT NULL PRIMARY KEY,
[foo] int NULL,
[bar] int NULL,
[nki] int NOT NULL
);
GO
/* Insert some random data */
INSERT INTO [dbo].[my_table] (foo, bar, nki)
SELECT TOP (100000)
ABS(CHECKSUM(NewId())) % 14,
ABS(CHECKSUM(NewId())) % 20,
n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
FROM
sys.all_objects AS s1
CROSS JOIN
sys.all_objects AS s2
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
ON [dbo].[my_table] ([nki] ASC);
GO
Se eu buscar todos os registros ordenados por [nki]
(Índice sem cluster):
SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;
SQL Server Execution Times: CPU time = 266 ms, elapsed time = 493 ms
O otimizador escolhe o índice em cluster e aplica um algoritmo de classificação.
Mas se eu forçá-lo a usar o índice não agrupado:
SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS TIME OFF;
SQL Server Execution Times: CPU time = 311 ms, elapsed time = 188 ms
Em seguida, ele usa índice não clusterizado com uma pesquisa de chave:
Obviamente, se o índice não agrupado em cluster for transformado em um índice de cobertura:
CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
ON [dbo].[my_table] ([nki] ASC)
INCLUDE (id, foo, bar);
GO
Em seguida, ele usa apenas este índice:
SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;
SQL Server Execution Times: CPU time = 32 ms, elapsed time = 106 ms
Questão
- Por que o SQL Server usa o índice clusterizado mais um algoritmo de classificação em vez de usar um índice não clusterizado, mesmo que o tempo de execução seja 38% mais rápido no último caso?
Respostas:
Como o SQL Server usa um otimizador baseado em custos com base em estatísticas, não em informações de tempo de execução.
Durante o processo de estimativa de custos para esta consulta, ele realmente avalia o plano de pesquisa, mas estima que será necessário mais esforço. (Observe o "Custo estimado da subárvore" ao passar o mouse sobre SELECT no plano de execução). Isso também não é necessariamente uma suposição ruim - na minha máquina de teste, o plano de pesquisa leva 6X a CPU da classificação / varredura.
Veja a resposta de Rob Farley sobre por que o SQL Server pode custar mais caro ao plano de pesquisa.
fonte
Se você comparar o número de leituras necessárias em 100.000 pesquisas com o que está envolvido em uma classificação, poderá ter uma ideia rápida sobre por que o Query Optimizer calcula que a Classificação CIX + seria a melhor opção.
A execução da Pesquisa acaba sendo mais rápida porque as páginas lidas estão na memória (mesmo que você limpe o cache, você tem muitas linhas por página, portanto, você está lendo as mesmas páginas repetidamente, mas com diferentes quantidades de fragmentação ou pressão de memória diferente de outra atividade, pode não ser o caso). Realmente não seria preciso muito para que o CIX + Sort fosse mais rápido, mas o que você está vendo é que o custo de uma leitura não leva em consideração o custo relativo de acessar as mesmas páginas repetidamente.
fonte
Decidi me aprofundar um pouco nessa questão e descobri alguns documentos interessantes falando sobre como e quando usar ou talvez melhor, não forçar o uso de um índice não agrupado.
Conforme sugerido pelos comentários de John Eisbrener , um dos blogs mais citados , mesmo em outros blogs, é este artigo interessante de Kimberly L. Tripp:
mas não é o único, se você estiver interessado, consulte estas páginas:
Como você pode ver, todos eles se movem em torno do conceito do ponto de tombamento .
Citado no artigo da KL Tripp
Quando o SQL Server usa um índice não agrupado em cluster, basicamente ele obtém uma lista de ponteiros para as páginas da tabela base. Em seguida, ele usa esses ponteiros para recuperar as linhas com uma série de operações denominadas RID (pesquisas de identificação de linha). Isso significa que, pelo menos, usará tantas leituras de página quanto o número de linhas retornadas, e talvez mais. O processo é um pouco semelhante com um índice clusterizado como a tabela base, com o mesmo resultado: mais leituras.
Mas quando esse ponto de inflexão ocorre?
Claro que, como a maioria das coisas nesta vida, depende ...
Não é sério, ocorre entre 25% e 33% do número de páginas na tabela, dependendo de quantas linhas por página. Mas há mais fatores que você deve considerar:
Citado no artigo ITPRoToday
Agora, se eu executar minhas consultas novamente usando estatísticas IO:
A segunda consulta precisa de mais leituras lógicas que a primeira.
Devo evitar o índice não agrupado?
Não, um índice em cluster pode ser útil, mas vale a pena dedicar tempo e fazer um esforço extra analisando o que você está tentando obter com ele.
Citado no artigo da KL Tripp
fonte