哪些列通常可以构成良好的索引?


98

作为“ 什么是索引,以及如何使用它们来优化数据库中的查询? ” 的后续尝试,在尝试了解索引的地方,哪些列是良好的索引候选者?专门针对MS SQL数据库?

经过一番谷歌搜索后,我读到的所有内容都表明,通常增加且唯一的列构成了很好的索引(例如MySQL的auto_increment之类的东西),我理解这一点,但是我使用的是MS SQL,并且我将GUID用于主键,所以看起来索引不会使GUID列受益...


怎么样一个“烹饪书”: mysql.rjweb.org/doc.php/index_cookbook_mysql
Rick James

Answers:


110

索引在查询优化和快速从表中搜索结果中可以发挥重要作用。因此,选择要索引的列是最重要的步骤。我们可以考虑在两个主要位置建立索引:WHERE子句中引用的列和JOIN子句中使用的列。简而言之,应该对这些列进行索引,以便您根据这些列搜索特定记录。假设我们有一个名为Buyers的表,其中SELECT查询使用如下索引:

SELECT
 buyer_id /* no need to index */
FROM buyers
WHERE first_name='Tariq' /* consider to use index */
AND last_name='Iqbal'   /* consider to use index */

由于在“选择”部分中引用了“ buyer_id”,因此MySQL不会使用它来限制所选行。因此,没有必要对其进行索引。下面是另一个示例,与上面的示例几乎没有什么不同:

SELECT
 buyers.buyer_id, /* no need to index */
 country.name    /* no need to index */
FROM buyers LEFT JOIN country
ON buyers.country_id=country.country_id /* consider to use index */
WHERE
 first_name='Tariq' /* consider to use index */
AND
 last_name='Iqbal' /* consider to use index */

根据上面的查询first_name,last_name列可以索引,因为它们位于WHERE子句中。另外,可以考虑将国家表中的另一个字段country_id用作索引,因为它位于JOIN子句中。因此可以在WHERE子句或JOIN子句中的每个字段上考虑索引。

下面的列表还提供了一些技巧,打算在表中创建索引时应始终牢记:

  • 仅索引WHERE和ORDER BY子句中所需的那些列。索引列过多将导致一些缺点。
  • 尝试利用MySQL的“索引前缀”或“多列索引”功能。如果创建索引,例如INDEX(first_name,last_name),请不要创建INDEX(first_name)。但是,不建议在所有搜索情况下都使用“索引前缀”或“多列索引”。
  • 对于要考虑建立索引的那些列,请使用NOT NULL属性,以便永远不会存储NULL值。
  • 使用--log-long-format选项可以记录未使用索引的查询。这样,您可以检查此日志文件并相应地调整查询。
  • EXPLAIN语句可帮助您揭示MySQL如何执行查询。它显示了表的连接方式和顺序。这对于确定如何编写优化查询以及是否需要对列进行索引非常有用。

更新(2015年2月23日):

任何索引(好/坏)都会增加插入和更新时间。

根据您的索引(索引数和类型),搜索结果。如果您的搜索时间由于索引而增加,那么索引不好。

在任何书籍中,“索引页面”都可能具有章节开始页面,主题页面编号开始,子主题页面开始。索引页面中的一些说明会有所帮助,但更详细的索引可能会使您感到困惑或恐惧。索引也有内存。

索引选择应该是明智的。请记住,并非所有列都需要索引。


感谢Somnath,这是否意味着仅应为计划使用的列创建索引WHEREJOINS或者HAVING
穆罕默德·巴巴尔

3
是的,对计划使用WHERE,JOINS或HAVING的列使用索引。但也要记住,所有条件列都不需要索引。有时条件列仅使用一次,因此它可能不需要索引,而其他条件列在许多查询中使用,因此更喜欢为该列建立索引。
Somnath Muluk

1
将TL; DR部分中的“在WHERE子句中引用的列和在JOIN子句中使用的列”放入答案中将会受益。
jpmc26

因此,您说的是,如果在我的WHERE子句中我正在检查一个字段的值,其中该字段的列只能采用两个值,那么我应该索引该二进制列?这似乎是错误的。
AjaxLeung

@AjaxLeung:记住Knuth的格言:“过早的优化是所有邪恶的根源”。您可以在二进制列上建立索引,但它应取决于所需的开销(例如插入,更新时间)。如果您的业务逻辑经常依赖于该二进制开关,则可能要求二进制列具有索引。
Somnath Muluk '18

20

有些人在这里回答了类似的问题:您如何知道什么是好的索引?

基本上,这实际上取决于您将如何查询数据。您需要一个索引,以快速识别与查询相关的数据集的一小部分。如果您从不按日期戳查询,则即使它是唯一的,也不需要索引。如果您要做的只是获取在特定日期范围内发生的事件,那么您肯定想要一个。在大多数情况下,关于性别的指数是没有意义的-但是,如果您要做的只是获得有关所有男性的统计数据,以及分别获得有关所有女性的统计数据,那么可能值得您花些时间来创建一个。弄清楚您的查询模式是什么,访问哪个参数可以最大程度地缩小搜索空间,这就是您的最佳索引。

还要考虑一下您创建的索引的种类-B树对大多数事情都适用,并且允许范围查询,但是哈希索引可以使您直截了当地(但不允许范围)。其他类型的索引具有其他优点和缺点。

祝好运!


9

这完全取决于您希望对表进行哪些查询。如果您要求X列的所有行都具有特定值,那么如果无法使用索引,则必须进行全表扫描。

在以下情况下,索引将很有用:

  • 一列或多列具有高度的唯一性
  • 您经常需要为该列寻找某个值或值的范围。

在以下情况下它们将无用:

  • 您正在表中选择很大的%(> 10-20%)行
  • 额外的空间使用是一个问题
  • 您想要最大化插入性能。表上的每个索引都会降低插入和更新性能,因为每次数据更改时都必须更新它们。

主键列通常非常适合索引,因为它们是唯一的并且通常用于查找行。


字符串搜索,其中值可以在字符串内的任何位置,这可能会使它不使用那些索引。
亚瑟·托马斯

5

一般而言(我不使用mssql,因此无法具体注释),主键可以作为良好的索引。它们是唯一的,并且必须指定一个值。(此外,主键会建立良好的索引,因此通常它们会自动创建一个索引。)

索引实际上是已排序以允许二进制搜索(比线性搜索快得多)的列的副本。数据库系统可能会使用各种技巧来进一步加快搜索速度,尤其是当数据比简单数字复杂时。

我的建议是最初不要使用任何索引并配置您的查询。如果经常执行特定查询(例如,按姓氏搜索人),请尝试再次在相关属性和配置文件上创建索引。如果查询的速度明显提高,而插入和更新的速度降低得可以忽略不计,则保留索引。

(很抱歉,如果我要重复您在其他问题中提到的内容,我以前没有碰到过。)


5

应该定期用于从表中提取数据的任何列都应建立索引。

这包括:外键-

select * from tblOrder where status_id=:v_outstanding

描述性字段-

select * from tblCust where Surname like "O'Brian%"

列不必是唯一的。实际上,当搜索异常时,您可以从二进制索引中获得非常好的性能。

select * from tblOrder where paidYN='N'

您明确提到外键确实为我考虑了连接问题清除了一切。
pfabri

3

这确实取决于您的查询。例如,如果您几乎只写一个表,那么最好不要有任何索引,它们只会减慢写入速度,并且永远不会被使用。您用来与另一个表联接的任何列都是索引的理想选择。

另外,请阅读有关缺失索引功能。它监视对数据库使用的实际查询,并可以告诉您哪些索引可以提高性能。


3

GUID列不是索引的最佳选择。索引最适合具有可赋予某些有意义顺序(即排序(整数,日期等))的数据类型的列。

列中的数据是否通常会增加并不重要。如果在列上创建索引,则索引将创建它自己的数据结构,该数据结构将简单地引用表中的实际项目,而无需考虑存储顺序(非聚集索引)。然后,例如可以对索引数据结构执行二进制搜索以提供快速检索。

也可以创建一个“聚簇索引”,以物理方式对数据进行重新排序。但是,每个表只能有其中之一,而您可以有多个非聚集索引。


好吧,这种方式并不完全准确。您可以在GUID列上轻松创建常规的非聚集索引-为什么不呢?如果将GUID用作聚类键(例如,用于CLUSTERED INDEX),则GUID有一个很大的缺点-使用起来很麻烦。
marc_s

1

经验法则是在WHERE,ORDER BY和GROUP BY子句中经常使用的列,或者似乎经常在联接中使用的列。请记住,我指的是索引,不是主键

不要给出“香草般的”答案,但这实际上取决于您如何访问数据


1

您的主键应始终是索引。(实际上,如果它没有被MS SQL自动索引,我会感到惊讶。)您还应该自己索引SELECTORDER频繁索引;它们的目的是快速查找单个值和快速排序。

索引too许多列的唯一真正危险是减慢大型表中对行的更改,因为索引也都需要更新。如果您真的不确定要索引的内容,只需对最慢的查询进行计时,查看最常使用的列,然后对其进行索引。然后看看它们有多快。


1

由于多种原因,按升序或降序排列的数字数据类型是好的索引。首先,与字符串(varchar,char,nvarchar等)相比,数字的求值速度通常更快。其次,如果未对值进行排序,则可能需要重新排列行和/或页面以更新索引。那是额外的开销。

如果您使用的是SQL Server 2005,并且开始使用uniqueidentifiers(引导),并且不需要它们具有随机性,请检查顺序的uniqueidentifier类型。

最后,如果您正在谈论聚簇索引,则是在谈论物理数据的种类。如果您有一个字符串作为聚簇索引,那可能会很难看。


0

如果使用的是GUID,它甚至应该更快。假设您有记录

  1. 100
  2. 200
  3. 3000
  4. ....

如果您有一个索引(二进制搜索,则可以在O(lg n)时间内找到要查找的记录的物理位置,而不是顺序搜索O(n)时间。这是因为您不知道自己拥有哪些记录在你的桌子上。


0

最佳索引取决于表的内容以及您要完成的工作。

以一个具有成员社会安全号的主键的成员数据库为例。之所以选择SS,是因为应用程序优先级是通过这种方式引用个人的,但是您还想创建一个搜索功能,该功能将利用成员的名字和姓氏。然后,我建议在这两个字段上创建一个索引。

您应该首先找出要查询的数据,然后确定需要为哪些数据建立索引。

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.