对于每种类型的查询,我都需要单独的索引,还是一个多列索引可以工作?


22

我已经有点知道这个问题的答案了,但是我总是觉得好像我还需要进一步探讨这个话题。

我的基本理解是,一般而言,仅包含您可能在任何给定时间查询/排序的所有字段的单个索引可能不太有用,但是我已经看到了这种类型的东西。就像这样,有人想:“好吧,如果我们将所有这些东西都放在一个索引中,数据库就可以使用它来查找所需的东西”,而从未见过针对某些实际查询运行的执行计划。

想象一个这样的表:

id int pk/uid
name varchar(50)
customerId int (foreign key)
dateCreated datetime

我可能会看到包含namecustomerIddateCreated字段的单个索引。

但是我的理解是,这样的索引不会在查询中使用,例如:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

对于这样的查询,在我看来,一个更好的主意是使用包括customerIdand dateCreated字段的索引,该customerId字段为“ first”。这将创建一个索引,该索引将以某种方式组织数据,以使该查询可以快速找到所需内容(按所需顺序)。

我看到的另一件事,也许与第一件事一样频繁,是每个字段上的单独索引。所以,每一个上namecustomerIddateCreated领域。

与第一个示例不同,在我看来,这种安排有时至少部分有用。查询的执行计划可能表明,至少它是使用上的索引customerId来选择记录,但没有使用带有dateCreated字段的索引来对记录进行排序。


我知道这是一个广泛的问题,因为对任何特定表集上的任何特定查询的特定答案通常是查看执行计划说的将要执行的操作,否则将表和查询的详细信息纳入其中帐户。另外,我知道这取决于查询的运行频率,而不是为其维护特定索引的开销。

但是我想我要问的是作为索引的一般“起点”,为特定的,经常被拉的查询以及WHERE或ORDER BY子句中的字段具有特定索引的想法是否有意义?

Answers:


27

没错,示例查询将不使用该索引。

如果以下情况,查询计划者将考虑使用索引:

  • 查询中引用了其中包含的所有字段
  • 引用了一些从头开始的字段

它将无法使用以查询未使用的字段开头的索引。

因此,对于您的示例:

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]在存在索引时才使用索引的查询。尽管使用just [customerId]会比使用复合索引更有效,但最终可以通过让两个索引竞争RAM中的空间而不是一个来缓解这种情况(尽管如果您的整个正常工作集很容易适合RAM,则这种额外的内存竞争可能不会缓解)一个问题)。


+1; 很棒的信息,特别是提醒(我往往会忘记!),即计划者有时只需要使用复合索引进行查询时就可以使用复合索引。
Andrew Barber

6

要回答您的原始问题,是的,必须围绕查询设计索引,而不仅仅是。索引中字段的顺序至关重要。设计单个索引以使它对于多个查询而言是最佳的,这比较困难,您将不得不权衡取舍。

关于第二点,是的,在单个字段上的一堆索引很烦人。我一直在我的环境中看到它,通常这对我来说是一个危险信号,即开发团队尚未与DBA合作设计适当的索引。

我设计索引的策略是索引:

  • WHERE中使用的字段(按选择顺序)
  • ORDER BY中使用的字段
  • 包括其他字段(如有必要)以形成覆盖索引

因此,对于您的示例:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

我可能会在(CustomerID,dateCreated)INCLUDE(id,name)上设计一个索引。此覆盖索引意味着查询永远不必访问原始表,从而极大地提高了性能。

但是,此示例几乎简单了。仅仅(CustomerID)上的纯朴索引也将表现得差不多(假设每个客户只有一个代表,因此只需要对表进行单个书签查找)。实际对(CustomerID,ID)进行聚簇索引也可能是有益的,这取决于针对该表运行的其他查询。


+1表示“索引必须围绕查询设计,而不仅仅是表”,其余答案则是+1,例如注意该示例非常简单。
Andrew Barber
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.