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

Nat*_*ate 19 index sql-server

我有 Log 和 LogItem 表;我正在编写一个查询来从两者中获取一些数据。有数千个,Logs每个Log最多可以有 125 个LogItems

有问题的查询很复杂,所以我跳过它(如果有人认为它很重要,我可以发布它),但是当我运行 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])
Run Code Online (Sandbox Code Playgroud)

只是为了好玩,我创建了这个新索引并运行了查询,令我惊讶的是,我的查询现在需要大约 1 秒才能运行,而之前是 10+ 秒。

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

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

GSe*_*erg 21

索引中列的顺序很重要。如果过滤需要索引中的第 1 列和第 4 列,则索引将无济于事。它仅在按前 N 个连续列过滤时有用。

这是因为索引是一棵树。你不能有效地选择树在那里的所有节点column3 = something,因为它们散布所有其他的地方,属于不同的价值观column1column2。但是,如果您知道column1并且也知道,column2在树中找到正确的分支是轻而易举的事。


Bra*_*vic 12

指数的领先优势很重要。

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

如果您有“漏洞”,例如,如果您在ParentLogID和 上搜索DatabaseModified,但只有在 上有索引{ParentLogID, DateModified, Name, DatabaseModified},那么只能{ParentLogID}有效利用索引的一部分。

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

  • @Nate - 正确。把它想象成一本电话簿。如果您只知道某人的名字,则不翻阅整本书是不可能找到的,因为它是按姓氏、名字组织的 (8认同)