Mar*_*cus 2 index sql-server t-sql index-tuning
对于下面的查询,我试图弄清楚为什么 SQL Server 在 sysjobhistory 表上建议的索引(也是导致查找的索引)是在 Job_Id 列上创建的,其中包括其他列:
Job_Id 包括(Run_date、Run_time、Instance_id)
据我了解,where 子句中的列应该出现在索引键中,以便可以进行搜索。Run_date 和 Run_time 出现在下面查询的 where 子句中,那么我们为什么可以将它们包含在索引中而不是将它们作为键列呢?
查询:
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())
Run Code Online (Sandbox Code Playgroud)
注意:我没有使用联接,因为该查询是 cte 的一部分,然后我从中删除,因此不可能进行联接。
因为缺少索引建议有点糟糕,这就是原因。
唯一最终出现在索引推荐的键中的列是 where 子句中的列。查询中使用的可以从索引排序中受益的其他列被归入包含列。
更糟糕的是,关键列的顺序完全得不到爱或喜爱。当然,它们被分组为等式 ( =, IS NULL) 和不等式 ( >, >=, <, <=, <>, IS NOT NULL) 谓词,但每组中的列顺序基于表定义中的序号位置。
将建议与查询计划中最慢的部分进行比较时,缺少索引可能几乎没有任何好处,并且可能会显示在数据库中无需维护其他对象而很快完成的查询中。
当 SQL Server 竭尽全力为您创建索引时,丢失的索引请求也会丢失。
对于您的问题,更多一点是,索引键列不考虑不可SARGable where 子句表达式,因为不存在寻找这些列中的值的策略,即使它们位于索引的键中。
以下是一些查询示例:
SELECT
c = COUNT_BIG(*)
FROM dbo.Posts AS p
WHERE p.OwnerUserId = 22656
AND p.LastEditDate >= '20080101';
SELECT
c = COUNT_BIG(*)
FROM dbo.Posts AS p
WHERE p.OwnerUserId = 22656
AND ISNULL(p.LastEditDate, '19000101') >= '20080101';
Run Code Online (Sandbox Code Playgroud)
缺少的索引请求有所不同,因为在第二个查询中,谓词 onLastEditDate包装在ISNULL函数中:
换句话说,缺失的索引请求有点像一个孩子说他们饿了然后要糖果。