我对索引还很陌生,刚刚开始学习查询计划等。我正在研究这个特定的查询,它一直建议我创建以下索引:
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[Company] ([CreatedById],[TenantId],[CreatedDate])
我已经创建了以下索引:
CREATE NONCLUSTERED INDEX [IX_Company_Tenant]
ON [dbo].[Company] ([TenantId],[UserId],[CreatedDate])
我想知道的是,如果我将已经创建的索引更改为:,是否会获得相同的速度提升结果:
CREATE NONCLUSTERED INDEX [IX_Company_Tenant]
ON [dbo].[Company] ([TenantId],[UserId],[CreatedDate], [CreatedByID])
而不是创建查询存储建议的索引?
编辑
即使应用了第三个索引:
CREATE NONCLUSTERED INDEX [IX_Company_Tenant]
ON [dbo].[Company] ([TenantId],[UserId],[CreatedDate], [CreatedByID])
我仍然得到相同的建议索引。
答案1
首先,确保在创建索引之间转储该查询的缓存计划。最核心的选项是执行缓存刷新(数据库缓存FREEPROCCACHE) 但您也可以查找计划句柄并只执行特定的一个。我还建议在试验期间删除非聚集索引 - 如果您在这个表上有三个索引,并且都试图加速同一个查询,那么这不是最好的情况。
在考虑创建索引时,请记住 SQL 为您提供的索引创建建议价值有限。SQL 通常正确地表示“我可以使用索引做得更好”,但它实际上没有很好的方法来告诉您最适合您需求的确切索引。
大多数情况下,它会给出次优的列顺序。很多时候它会错过有用的列,或者告诉你放入了太多的列。
一般来说,您需要对导致需要索引的查询有充分的了解,然后创建适合该查询的索引。大多数查询都采用针对某些特定记录集的形式,因此索引中的列按最能找到所需数据的顺序排列。换句话说,如果一列可以消除所有可能结果的 95%,而另一列可以消除 20% 的结果,则将 95% 的列放在首位。
举一个简单的例子,如果我有一个查询,按日期选择一小部分(1%)记录,并通过 50% 的记录所具有的标志消除一些剩余的记录,那么我最好先按日期对索引列进行排序,然后再按标志进行排序。反过来做会让我为相同的最终结果执行更多的工作。
在不了解您的数据的情况下查看您的查询,我猜测它的一个相当不错的索引将是:
CREATE NONCLUSTERED INDEX [IX_Company_Tenant]
ON [dbo].[Company] ([CreatedDate],[CreatedByID],[TenantId])
这是一篇很好的博客文章,对此进行了更深入的解释 -https://www.brentozar.com/archive/2019/10/how-to-think-like-the-sql-server-engine-adding-a-nonclustered-index/
答案2
您必须按照建议的确切列顺序(或技术上几乎等同的列顺序)创建索引。
列顺序有时/通常对特定查询的索引的可用性和效率很重要。
在上述情况下,重要的是在这些字段CreatedDate
后面CreatedByID
或TenantId
甚至直接后面(因此没有UserId
中间)有,以允许 SQL Server 直接跳转到索引块CreatedByID
,TenantId
然后CreatedDate
在该列的连续顺序条目中找到请求的起始值并读取所有行引用,一个接一个地滚动索引,直到达到请求的CreatedDate
结束值(并为找到的每一行增加计数器)。
与此相反,请考虑调整后的索引。
SQL Server 可以找到请求的区域TenantId
。 但是它必须读取该区域的所有条目TenantId
并检查是否CreateDate
在范围内,如果在范围内,则必须检查是否CreatedByID
满足查询条件。 可能需要进行这些检查的行数可能很多,具体取决于表大小和数据分布。