Para a consulta abaixo, estou tentando descobrir por que o índice sugerido pelo SQL Server na tabela sysjobhistory, que também é o índice que resulta em uma busca, foi criado na coluna Job_Id com as outras colunas incluídas:
Job_Id inclui (Run_date, Run_time, Instance_id)
No meu entender, as colunas em uma cláusula where devem estar presentes na chave do índice para que as buscas sejam possíveis. Run_date e Run_time estão presentes na cláusula where da consulta abaixo, então como podemos colocá-los na inclusão de um índice em vez de tê-los como colunas-chave?
A pergunta:
SELECT TOP 10000 run_date
FROM msdb.dbo.sysjobhistory sh
WHERE EXISTS (SELECT 1 FROM msdb.dbo.sysjobs sj WHERE sh.job_id = sj.job_id
AND EXISTS (SELECT 1 FROM msdb.dbo.sysjobschedules sjs WHERE sjs.job_id = sj.job_id
AND EXISTS (SELECT 1 FROM msdb.dbo.sysschedules ss WHERE ss.schedule_id = sjs.schedule_id
AND ss.freq_subday_type = 2
AND ss.freq_subday_interval = 10 )))
AND CAST(CAST([run_date] AS CHAR(8)) + ' ' + STUFF(STUFF(RIGHT('000000' + CAST([run_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') AS DATETIME) < dateadd(hh,-12,getdate())
Nota: não estou usando junções porque esta consulta faz parte de um cte do qual eu excluo, portanto, junções não são possíveis.
Por que, ah, por que, ah, por que
Porque as recomendações de índice ausentes são uma droga, é por isso.
As únicas colunas que terminarão na chave de uma recomendação de índice são as colunas da cláusula where. Outras colunas usadas na consulta que poderiam se beneficiar da ordenação do índice são relegadas às inclusões.
Para piorar a situação, a ordem das colunas principais não recebe absolutamente nenhum amor ou carinho. Claro, eles são agrupados em predicados de igualdade ( , )
=
eIS NULL
desigualdade ( ,,,,,, ) , mas a ordem das colunas em cada grupo é baseada na posição ordinal na definição da tabela.>
>=
<
<=
<>
IS NOT NULL
Os índices ausentes podem fornecer pouco ou nenhum benefício ao comparar a recomendação com as partes mais lentas de um plano de consulta e podem aparecer para consultas que terminam muito rapidamente sem um objeto adicional para manter no seu banco de dados.
Solicitações de índice ausentes também estarão ausentes quando o SQL Server se esforçar para criar um índice para você.
Porém, para a sua pergunta um pouco mais, é que as expressões da cláusula where não-SARGable não são consideradas para colunas-chave do índice, porque não existe nenhuma estratégia para buscar valores nessas colunas, mesmo que estivessem na chave do índice.
Aqui estão alguns exemplos de consultas:
As solicitações de índice ausentes diferem porque na segunda consulta, o predicado on
LastEditDate
é encapsulado naISNULL
função:Em outras palavras, uma solicitação de índice ausente é como quando uma criança diz que está com fome e depois pede um doce.
Job_Id
é incluído e indexado porque é usado na condição JOIN.Run_date, Run_time
são incluídos porque são usados na expressão da condição de subconsulta mais interna eRun_date
também são incluídos na lista de saída, portanto, não precisam ser classificados. Seus valores devem ser extraídos do índice e o servidor não precisa acessar o corpo da tabela durante a execução desta consulta.Não sei por que
Instance_id
está incluído - não é usado na consulta. Talvez o mesmo índice também melhore alguma outra consulta onde esta coluna é usada?PS. Você usa
TOP 10000
, mas não há cláusula ORDER BY... você realmente precisa de QUALQUER 10 mil linhas de todas as selecionadas pela consulta?Você não usa essas colunas diretamente, elas são usadas na expressão. Isto evita qualquer busca de índice, apenas a varredura de índice é possível. Portanto, eles podem ser indexados ou incluídos. Mas quando eles são indexados, o servidor deve realizar trabalho adicional e desnecessário ao alterar os dados devido a etapas adicionais de classificação.
PS. Revertendo sua condição - as colunas são usadas imediatamente, enquanto os valores referenciados obtidos de GETDATE() são extraídos e formatados com as expressões correspondentes. Isso melhorará sua consulta. Talvez isso faça com que a indexação dessas colunas seja utilizada. Do outro lado você obterá uma condição que combina AND e OR, portanto a busca de índice pode ser problemática. Você testaria na prática.
PPS. Armazenar os componentes de data e hora de um carimbo de data/hora em colunas diferentes não é uma boa prática. Armazenar o valor como um cálculo DATETIME e componentes separados na consulta ou na coluna gerada pode ser mais útil.