为什么这些列在索引的 include 子句中指定而不是作为键列

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 的一部分,然后我从中删除,因此不可能进行联接。

Eri*_*ing 9

为什么哦为什么哦为什么

因为缺少索引建议有点糟糕,这就是原因。

唯一最终出现在索引推荐的键中的列是 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函数中:

坚果

换句话说,缺失的索引请求有点像一个孩子说他们饿了然后要糖果。