Sql 当现有索引包含新索引中的所有列时,为什么创建这个新索引会大大提高性能?

Sql 当现有索引包含新索引中的所有列时,为什么创建这个新索引会大大提高性能?,sql,sql-server,database,tsql,indexing,Sql,Sql Server,Database,Tsql,Indexing,我有日志和LogItem表;我正在编写一个查询,从这两个方面获取一些数据。有数千个日志,每个日志最多可以有125个登录项 所讨论的查询很复杂,所以我跳过它(如果有人认为它很重要,我可能会发布它),但当我运行SSMS估计查询计划时,它告诉我一个新的非聚集索引可以将性能提高100% Existing Index: Non-clustered Key Colums (LogItem): ParentLogID, DateModified, Name, DatabaseModified Query P

我有日志和LogItem表;我正在编写一个查询,从这两个方面获取一些数据。有数千个
日志
,每个
日志
最多可以有125个
登录项

所讨论的查询很复杂,所以我跳过它(如果有人认为它很重要,我可能会发布它),但当我运行SSMS估计查询计划时,它告诉我一个新的非聚集索引可以将性能提高100%

Existing Index: Non-clustered
Key Colums (LogItem): ParentLogID, DateModified, Name, DatabaseModified

Query Plan Recommendation
CREATE NONCLUSTERED INDEX [LogReportIndex]
ON [dbo].[LogItem] ([ParentLogID],[DatabaseModified])
只是为了好玩,我创建了这个新索引并运行了查询。令我惊讶的是,现在我的查询需要1秒钟才能运行,而之前是10秒以上

我假设我的现有索引将覆盖这个新查询,所以我的问题是,为什么在新查询中使用的唯一列上创建新索引会提高性能?我应该为我的
where
子句中使用的每一个唯一的列组合建立索引吗


注意:我不认为这是因为SQL Server正在缓存我的结果,在创建索引之前,我运行了大约25-30次查询,持续时间为10-15秒,在索引之后,持续时间为~1秒或更少。

索引中列的顺序很重要。如果筛选需要索引中的第1列和第4列,则索引不会有帮助。它仅在按前N个连续列进行筛选时有用


这是因为索引是一棵树。您无法有效地选择树中
column3=something
的所有节点,因为它们分散在所有其他位置,属于
column1
column2
的不同值。但是如果你也知道
column1
column2
,那么在树中找到正确的分支就很容易了。

索引的前沿是最重要的

只要您的查询被索引的前缘“覆盖”,它就会非常有效。数据库索引通常实现为B-树,B-树的结构规定搜索必须按特定顺序进行,这就是复合索引中字段的顺序很重要的原因

如果您有“漏洞”,例如,如果您在
ParentLogID
DatabaseModified
上搜索,但在
{ParentLogID,DateModified,Name,DatabaseModified}
上只有索引的
{ParentLogID}
部分可以有效利用


(注意:某些DBMS可以通过“跳过扫描”来利用
{DatabaseModified}
部分,但即使您的DBMS这样做,其效率也远低于常规索引访问)。

在创建其他非聚集索引之前,索引使用的实际执行计划显示了什么?性能提高了100%是什么?@Shark问得好,我不确定。这是我第一次进行性能调试。我一定会抓住这个机会。它所说的只是“缺少索引”和哪些字段。@JeffO这是SSMS所说的:“查询处理器估计实现以下索引可以将查询成本提高100%。”然后(通常)可以安全地假设我需要一个索引来表示“where”将要命中该表的子句?我曾经通过确保其他人的查询以正确的顺序使用索引,大大加快了查询速度。@Nate,是的。一些
where
s可能重叠,因此您可能有一个索引,可以很好地覆盖多个
where
s;或者,您可以忽略
where
子句的某些部分,因为对某个列进行索引无论如何都不会有帮助(低选择性);但大体上说,是的,你不想拥有比需要更多的索引。SQL必须维护的每个索引都会增加自身的开销。如果可以对WHERE子句进行重新排序,使其与现有索引上的前N列相匹配,那么在不添加额外索引的情况下,应该可以非常接近。@ChuckBlumreich
WHERE
子句中列的顺序并不重要。服务器将始终安排它们以充分利用现有索引。这只是一个索引包含所有必需的
,其中
列作为其第一列的问题。因此,如果我有
列(a、b、c、d、e、f)
,并且大多数查询都是
。。。其中A IN(…)和B=3
我的索引
索引(A,B,c,d)
这是一个好的索引,但如果我有
。。。其中A IN(…)和D=5
这就是我的新索引的原因,
索引(A,D)
大大提高了性能,对吗?@Nate-正确。把它想象成一本电话簿。如果你只知道一个人的名字,不翻阅整本书是不可能找到的,因为它是按姓氏组织的