简单的内部联接建议一个包含索引

简单的内部联接建议一个包含索引

问题描述:

我有这个简单的内部联接查询和其执行计划主表有大约34K记录和细节表有大约51K记录。但是这个简单的查询建议添加一个索引include(包含我包含在select中的所有主列)。我不期待这可能是什么原因和补救措施。简单的内部联接建议一个包含索引

DECLARE  
     @StartDrInvDate Date ='2017-06-01', 
     @EndDrInvDate Date='2017-08-31' 

    SELECT 
     Mastertbl.DrInvoiceID, 
     Mastertbl.DrInvoiceNo, 
     Mastertbl.DistributorInvNo, 
     PreparedBy, 
     detailtbl.BatchNo, detailtbl.Discount, 
     detailtbl.TradePrice, detailtbl.IssuedUnits, 
     detailtbl.FreeUnits 
    FROM 
     scmDrInvoices Mastertbl 
    INNER JOIN 
     scmDrInvoiceDetails detailtbl ON Mastertbl.DrInvoiceID = detailtbl.DrInvoiceID 
    WHERE 
     (Mastertbl.DrInvDate BETWEEN @StartDrInvDate AND @EndDrInvDate) 

enter image description here

我真正的好奇心就是为什么它是在暗示该指数 - 我通常看不到较大的表格

+0

随着行的数量如果您对目前的表现满意,您可以放心地忽略这个建议。 – Serg

+0

仅仅因为SQL Server要求这并不意味着你应该创建它。它基于它在特定查询上使用的执行计划的假设。尝试在Mastertbl.DrInvoiceID上添加非聚集索引并包含Mastertbl.DrInvDate。查看查询并播放其上的索引:) – dbajtr

+0

@Serg此查询实际上是需要一些时间的较大查询的一部分,并且该查询在我删除所有其他连接时提示此索引,并且我只剩下这部分并仍然建议相同的索引 – Zia

对于此查询此行为:

SELECT m.DrInvoiceID, m.DrInvoiceNo, m.DistributorInvNo, 
     PreparedBy, 
     d.BatchNo, d.Discount, d.TradePrice, d.IssuedUnits, d.FreeUnits 
FROM scmDrInvoices m INNER JOIN 
    scmDrInvoiceDetails d 
    ON m.DrInvoiceID = d.DrInvoiceID 
WHERE m.DrInvDate BETWEEN @StartDrInvDate AND @EndDrInvDate; 

我期望基本指标为:scmDrInvoices(DrInvDate, DrInvoiceID)scmDrInvoiceDetails(DrInvoiceID)。该索引将允许查询引擎快速识别与主表中的WHERE相匹配的行,然后查找scmDrInvoiceDetails中的对应值。

其余列可以包含在任一索引中,以便索引覆盖查询。 “封面”意味着所有列都在索引中,因此查询计划不需要引用原始数据页面。

上述策略是SQL Server建议的。

+0

是的,这些索引已经存在 – Zia

你也许可以看到它建议索引发票日期的逻辑;它对你想要的行数进行了一些计算,使其超出了它认为当前存在的行数,并且似乎该列上索引的选择性使其值得索引。如果你想要55,000中的3行,并且你希望它每5分钟一次,那么索引是有意义的。特别是如果该表的增长率意味着明年将有550万的3排。

包含建议可能更天真地建议将足够的附加数据与索引值相关联,这样可以从索引回答主表所需的整个数据集,而不会触及表 - 索引基本上是指向行中的行的指针表;当查询引擎使用索引来查找所需的所有行时,它仍然需要打开表来实际获取所需的数据。通过在索引中包含数据,您可以删除需要转到表中的表单,并且它有时是合理的,但不是其他表单(为创建许多索引,实质上复制大部分/全部表数据以便很少运行查询是浪费磁盘空间)。

也要考虑到,现在在调试工具中运行此查询的频率正在影响SQLServer对查询使用频率的看法。我经常发现我的SQLAzure门户提供索引建议,这要感谢开发者反复运行查询,调试它,当我真正知道在prod中,该查询将每月使用一次,因此我放弃了建立索引的建议包括大多数表格,当直接“索引只搜索列”将做的很好,不包括必要的

因此,这些建议不应该盲目地被注意,因为SQLServer无法知道你打算使用这个或类似的查询在现实世界中的应用。索引创建和维护应该小心谨慎地进行;例如它可能是这个查询要求这个索引,另一个查询会希望在另一个列上有一个索引,但是在两个列上创建一个索引(按特定顺序),然​​后在任何查询搜索在索引为第二的列中,包括一个谓词,无论查询是否需要,它都会触及第一个索引列

例如,在您的发票表中,您有一列指示其是否已付费以及您的其他位置应用程序中有另一个查询可以计算未付发票的数量。即使状态谓词是冗余的,您也可以有两个索引 - 一个在发票日期(对于此查询)和一个对状态(对于该查询)或两个列(状态,日期)和该查询中的一个具有WHERE status = 'unpaid' AND date between...的谓词。为什么它可能是多余的?假设你知道你只会从上周选择尚未发出的发票,所以只能是未付款的。这就是我的意思,“对索引进行深思熟虑” - 你知道很多有关你的应用的信息SQLServer永远无法解决问题。通过在“从上周获取发票”查询中包含冗余状态列(即使状态在逻辑上是冗余的),您允许查询引擎使用首先按状态排序的索引,然后按日期排序。这意味着你可以摆脱不得不只维持一个指标,并且它可以通过两个查询

索引维护和创造的逻辑中可以是全职工作..;)