我是否需要每种类型的查询索引,还是一个多列索引工作?
-
16-10-2019 - |
题
我已经有点知道这个问题的答案,但是我总是觉得好像我需要更多地讨论这个主题。
我的基本理解是,一般而言,一个单个索引只包含您可能在任何给定时间查询/排序的所有字段都不可能有用,但是我已经看到了这种类型的东西。就像有人认为:“好吧,如果我们只是将所有这些东西放在索引中,数据库可以使用它来找到所需的东西”,而没有看到某些实际查询的执行计划。
想象一下这样的桌子:
id int pk/uid
name varchar(50)
customerId int (foreign key)
dateCreated datetime
我可能会看到一个索引,包括 name
, customerId
和 dateCreated
字段。
但是我的理解是,这样的索引不会在例如:
SELECT [id], [name], [customerId], [dateCreated]
FROM Representatives WHERE customerId=1
ORDER BY dateCreated
对于这样的查询,在我看来,一个更好的主意将是一个索引 customerId
和 dateCreated
领域,带有 customerId
字段是“第一”。这将创建一个索引,该索引将以此查询可以快速找到所需的方式组织数据 - 按照其需要的顺序。
我看到的另一件事,也许和第一个一样频繁的是每个字段上的单个索引。所以,每个 name
, customerId
和 dateCreated
字段。
与第一个示例不同,在我看来,这种类型的安排至少在部分有用。查询的执行计划可能表明,至少它正在使用索引 customerId
选择记录,但它不是使用索引 dateCreated
字段对它们进行分类。
我知道这是一个广泛的问题,因为在任何特定表上的任何特定查询的具体答案通常都是为了查看执行计划所说的要做什么,否则请将表格的具体内容和查询纳入帐户。另外,我知道这取决于查询的频率可能与维护特定索引的开销相反。
但是我想我要问的是索引的一般“起点”,是否有特定的索引对特定的,经常被提出的查询和条款中的订单或顺序中的字段有意义?
解决方案
您是正确的,您的示例查询不会使用该索引。
查询计划者将考虑使用索引:
- 查询中引用了其中包含的所有字段
- 从一开始就引用了一些字段
它将无法利用从查询未使用的字段开始的索引。
因此,以您的示例:
SELECT [id], [name], [customerId], [dateCreated]
FROM Representatives WHERE customerId=1
ORDER BY dateCreated
它将考虑以下索引:
[customerId]
[customerId], [dateCreated]
[customerId], [dateCreated], [name]
但不是:
[name], [customerId], [dateCreated]
如果发现两者 [customerId]
和 [customerId], [dateCreated], [name]
它决定偏爱另一个的决定取决于索引统计数据,该索引统计数据取决于该领域数据平衡的估计。如果 [customerId], [dateCreated]
被定义,除非您给出相反的特定索引,否则应该比其他两个相比。
在我的经验中,看到一个为每个字段定义的一个索引并不少见,尽管这很少是最佳的,因为更新插入/更新的索引所需的额外管理以及存储它们所需的额外空间,但当一半的一半时就会浪费它们可能永远不会被使用 - 但是除非您的数据库看到写入重负载,否则表现即使有多余的索引也不会臭。
频繁查询的特定索引,否则由于表或索引扫描而导致的速度会很慢,但通常是一个好主意,尽管不要过度使用它,因为您可以将一个性能问题交换为另一个性能问题。如果您确实定义 [customerId], [dateCreated]
例如,作为索引,请记住,查询计划者将能够将其用于仅在公正上使用索引的查询 [customerId]
如果存在。同时使用 [customerId]
与使用化合物索引相比,这可能会通过在RAM中争夺空间而不是使用该化合物指数(尽管您的整个正常工作套件轻松地适合RAM)来减轻这种额外的记忆竞争可能不是问题) 。
其他提示
要回答您的原始问题,是的,必须围绕 查询, ,不只是 桌子. 。指数中的字段顺序至关重要。设计单个索引以最佳的多个查询更加困难,您将不得不进行权衡。
关于您的第二点,是的,单个字段上的一堆索引在令人讨厌的情况下很普遍。我一直都在我的环境中看到它,这通常是我的危险信号,即开发团队没有与DBA合作设计适当的索引。
我设计索引的策略是索引:
- 在哪里使用的字段(按选择性顺序)
- 按顺序使用的字段
- 包括其他字段(如有必要)进行覆盖索引
因此,以您的示例:
SELECT [id], [name], [customerId], [dateCreated]
FROM Representatives WHERE customerId=1
ORDER BY dateCreated
我可能会在(customerId,datecreated)上设计一个索引,包括(id,name)。该涵盖索引意味着查询永远不必击中原始桌子,从而大大提高了性能。
这个示例几乎是 也 简单,不过。 Just(CustomerID)上的天真索引也几乎也会执行(假设每个客户只有一个代表,因此只需要一个书签查找)。实际做一个甚至可能是有益的 聚类 索引ON(CustomerID,ID),具体取决于其他查询在表面上的其他查询。