MySQL索引-最佳做法是什么?


208

我已经在MySQL数据库上使用索引一段时间了,但是从未正确地了解过它们。通常,我会使用WHERE子句在要搜索或选择的任何字段上添加索引,但有时看起来并不那么黑白。

MySQL索引的最佳做法是什么?

情况/困境示例:

  • 如果一个表有六个列,并且所有列都是可搜索的,那么我应该对它们全部编制索引还是不对它们进行索引?

  • 索引对性能的负面影响是什么?

  • 如果我有一个VARCHAR 2500列,可以从我的网站的某些部分进行搜索,我应该对它进行索引吗?


5
您可能应该重新标记该问题。索引的选择是优化任何数据库模型的重要组成部分。和我的观点无关的PHP。
VGE 2010年


Answers:


242

您绝对应该花一些时间阅读索引,有关索引的文章很多,了解发生的事情很重要。

广义上讲,索引对表的行强加了顺序。

为简单起见,假设表只是一个大CSV文件。每当插入一行时,它就会插入到末尾。因此,表的“自然”顺序就是插入行的顺序。

想象一下,您已经在非常基本的电子表格应用程序中加载了CSV文件。该电子表格所做的只是显示数据,并按顺序对行编号。

现在,假设您需要在第三列中找到所有具有某些值“ M”的行。给定可用的资源,您只有一个选择。您扫描表,检查每一行的第三列的值。如果您有很多行,此方法(“表扫描”)可能需要很长时间!

现在想象一下,除了该表之外,您还有索引。该特定索引是第三列中的值的索引。该索引以某种有意义的顺序(例如,按字母顺序)列出了第三列中的所有值,并为它们中的每一个提供了该值出现的行号列表。

现在,您有一个很好的策略来查找第三列的值为“ M”的所有行。例如,您可以执行二进制搜索!表扫描要求您查看N行(其中N是行数),而二进制搜索仅要求您查看log-n索引条目,在最坏的情况下。哇,这肯定容易得多!

当然,如果您有此索引,并且要向表中添加行(最后,因为这是我们的概念表的工作方式),则需要每次都更新索引。因此,您在编写新行时需要做更多的工作,但是在搜索内容时可以节省大量时间。

因此,通常,索引在读取效率和写入效率之间产生折衷。没有索引,插入会非常快-数据库引擎只会在表中添加一行。添加索引时,引擎必须在执行插入操作时更新每个索引。

另一方面,读取变得更快。

希望能涵盖您的前两个问题(正如其他人回答的那样-您需要找到合适的平衡点)。

您的第三个场景要复杂一些。如果您使用的是LIKE,则索引引擎通常可以帮助您将读取速度提高到第一个“%”。换句话说,如果您正在选择WHERE列,例如'foo%bar%',则数据库将使用索引查找列以“ foo”开头的所有行,然后需要扫描该中间行集以找到子集包含“栏”。SELECT ... WHERE列之类的'%bar%'无法使用索引。我希望你能明白为什么。

最后,您需要开始考虑多个列上的索引。这个概念是相同的,并且其行为类似于LIKE的东西-本质上,如果您在(a,b,c)上有一个索引,则引擎将尽最大可能继续使用从左到右的索引。因此,对列a的搜索可能会使用(a,b,c)索引,就像对(a,b)的索引一样。但是,如果您在搜索WHERE b = 5 AND c = 1)时,引擎将需要进行全表扫描。

希望这可以帮助您有所了解,但是我必须重申,您最好花几个小时来深入研究能解释这些问题的好文章。阅读特定数据库服务器的文档也是一个好主意。查询计划者实现和使用索引的方式可以相差很大。


10
怎么样的FULLTEXT指标?他们可以提供类似条件的帮助LIKE '%bar%'吗?
Septagram 2013年

2
@Septagram- 如果是“单词” FULLTEXT可以帮助进行查询。 处理单词,而不是任意子字符串(也是如此)。 barFULLTEXTLIKE
里克·詹姆斯

@timdev明确回答了第一个问题的哪一部分?我可以检测到您有价值的答案的第一部分和第二部分(“ 希望涵盖您的前两个问题”的第一部分和第二部分)中回答的第二和第三个问题
曼努埃尔·乔丹,

1
@ManuelJordan-第一个问题没有简单的答案。这取决于您要如何在预期(或什至更好的是,观察到的)使用情况下权衡取舍。
timdev '19

57

查阅诸如“ 更多地掌握索引艺术”之类的演示。

更新12/2012:我发布了我的新演示文稿:真正如何设计索引。我在2012年10月在圣塔克拉拉的ZendCon和2012年12月在伦敦Percona Live上提出了这一点。

设计最佳索引是一个必须匹配您在应用程序中运行的查询的过程。

很难建议任何通用的规则,这些规则关于哪些列最适合索引,或者是否应该索引所有列,不索引任何列,哪些索引应该跨越多列等等,这取决于您需要运行的查询。

是的,有一些开销,所以您不应不必要地创建索引。但是,您应该创建索引,以使您需要快速运行的查询受益。索引的开销通常远远超过其好处。

对于VARCHAR(2500)列,您可能要使用FULLTEXT索引或前缀索引:

CREATE INDEX i ON SomeTable(longVarchar(100));

请注意,如果您正在搜索可能位于该长varchar中间的单词,常规索引将无济于事。为此,请使用全文索引。


3
非常感谢。slideshare.net/matsunobu/…确实非常有帮助。
比沙尔·波德尔



1
精彩的演讲(2012年的演讲)真正理解了索引的全部要点。
DarkteK

46

我不会在其他答案中重复一些好的建议,但会补充:

复合指数

您可以创建复合索引-包含多个列的索引。MySQL能够从使用这些留下的权利。因此,如果您有:

Table A
Id
Name
Category
Age
Description

如果您的复合索引按该顺序包含Name / Category / Age,则这些WHERE子句将使用索引:

WHERE Name='Eric' and Category='A'

WHERE Name='Eric' and Category='A' and Age > 18

WHERE Category='A' and Age > 18

不会使用该索引,因为必须从左到右使用所有内容。

说明

使用Explain / Explain Extended可以了解MySQL可以使用哪些索引以及它实际选择的索引。 MySQL 每个查询只使用一个

EXPLAIN EXTENDED SELECT * from Table WHERE Something='ABC'

慢查询日志

打开慢速查询日志以查看哪些查询运行缓慢。

宽列

如果您有一列很宽的列,其中大多数区别出现在前几个字符中,则只能使用索引中的前N个字符。示例:我们有一个ReferenceNumber列定义为varchar(255),但在97%的情况下,引用数为10个字符或更少。我将索引更改为仅查看前10个字符,并提高了性能。


我对最后一部分有疑问。我读过某个地方的文章,如果您使用VARCHAR创建一列,则应始终将其设置为255。您究竟该怎么做?
AlexioVay

20

如果一个表有六列,并且所有列都是可搜索的,那么我应该为它们全部编制索引还是都不为它们编制索引?

您是逐字段进行搜索还是某些搜索使用多个字段?搜索最多的字段是?什么是字段类型?(例如,在INT上,索引比在VARCHAR上更好地工作)您是否尝试对正在运行的查询使用EXPLAIN?

索引对性能的影响是什么

更新和插入将变慢。还有额外的存储空间要求,但是如今这通常并不重要。

如果我有一个VARCHAR 2500列,可以从我的网站的某些部分进行搜索,我应该对它进行索引吗

不可以,除非它是UNIQUE(这意味着它已经被索引),或者您只在该字段上搜索完全匹配(不使用LIKE或mySQL的全文本搜索)。

通常,我会在要使用WHERE子句搜索或选择的任何字段上添加索引

我通常会索引查询最多的字段,然后再索引INT / BOOLEAN / ENUM,而不是VARCHARS。别忘了,通常您需要在组合字段上创建索引,而不是在单个字段上创建索引。使用EXPLAIN,并检查慢速日志。


11

高效地加载数据:索引加快了检索速度,但减慢了插入和删除以及索引列中值的更新速度。也就是说,索引会减慢大多数涉及写入的操作。发生这种情况是因为写一行不仅需要写数据行,而且还需要更改任何索引。表的索引越多,需要进行的更改就越多,并且平均性能下降也就越大。大多数表接收许多读取而很少写入,但是对于写入百分比较高的表,索引更新的成本可能会很高。

避免使用索引:如果不需要特定的索引来帮助查询更好地执行,则不要创建索引。

磁盘空间:一个索引占用磁盘空间,而多个索引相应地占用更多空间。与没有索引相比,这可能导致您更快地达到表大小限制。尽可能避免使用索引。

要点:不要过度索引


5

在一般情况下,指数加速帮助数据库搜索,其使用额外的磁盘空间和减慢的缺点INSERT/ UPDATE/ DELETE查询。使用EXPLAIN并读取结果以了解MySQL使用索引的时间。

如果一个表有六列,并且所有列都是可搜索的,那么我应该为它们全部编制索引还是不为它们编制索引?

索引所有六列并不总是最佳实践。

(a)搜索特定信息时,您将使用这些列中的任何列吗?

(b)这些列的选择性是什么(与表上的记录总数相比,存储了多少个不同的值)?

MySQL使用基于成本的优化器,该优化器在执行查询时会尝试查找“最便宜”的路径。选择性低的领域不是很好的选择。

索引对性能的影响是什么?

已回答:额外的磁盘空间,插入-更新-删除期间性能降低。

如果我有一个VARCHAR 2500列,可以从我的网站的某些部分进行搜索,我应该对它进行索引吗?

尝试全文索引


4

1/2)索引可以加快某些选择操作的速度,但会减慢其他操作(如插入,更新和删除)的速度。这可以是一个很好的平衡。

3)使用全文索引或狮身人面像


为了防止slow down other operations like insert, update and deletes您可以使用START TRANSACTION; YOUR CODE HERE; COMMIT which可以帮助避免slowing down其他操作,因为它只会一次检查一个约束。注意:如果您使用REPLACE INTO和和SQL_MODE<> STRICT_ALL_TABLESTRADITIONALBulk Load则将忽略替换并插入重复项。
JayRizzo

并非所有MySQL引擎都支持事务。AFAIK,即使仅隐式使用事务,也会减慢DB操作的速度。我们需要根据实际性能进行设计的是一种半自动方式,用于分析(衡量性能)各种优化选择,包括索引和事务。
David Spector
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.