我已经在我的MySQL数据库上使用索引有一段时间了,但从来没有正确地学习过它们。一般来说,我把索引放在任何字段,我将搜索或选择使用WHERE子句,但有时它似乎不是那么黑和白。

MySQL索引的最佳实践是什么?

例子的情况/困境:

如果一个表有六列,并且它们都是可搜索的,我应该索引它们全部还是没有? 索引对性能的负面影响是什么? 如果我有一个varchar2500列,可以从我的网站的部分搜索,我应该索引它吗?


Load Data Efficiently: Indexes speed up retrievals but slow down inserts and deletes, as well as updates of values in indexed columns. That is, indexes slow down most operations that involve writing. This occurs because writing a row requires writing not only the data row, it requires changes to any indexes as well. The more indexes a table has, the more changes need to be made, and the greater the average performance degradation. Most tables receive many reads and few writes, but for a table with a high percentage of writes, the cost of index updating might be significant.

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

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

建议:不要过度索引


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

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


如果一个表有六列,他们都是可搜索的,我应该索引他们所有或没有

您是逐个字段搜索还是使用多个字段进行搜索? 哪些字段最常被搜索? 字段类型是什么?(例如,索引在int上比在VARCHARs上工作得更好) 您尝试过对正在运行的查询使用EXPLAIN吗?

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

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

如果我有一个varchar2500列,可以从我的网站的部分搜索,我应该索引它

不,除非它是唯一的(这意味着它已经被索引),或者你只搜索该字段的精确匹配(不使用LIKE或mySQL的全文搜索)。

通常我把索引放在任何字段,我将搜索或选择使用WHERE子句

我通常会索引查询次数最多的字段,然后是int / boolean / enum,而不是VARCHARS字段。不要忘记,通常需要在组合字段上创建索引,而不是在单个字段上创建索引。使用EXPLAIN,并检查慢日志。


看看像“更多掌握索引的艺术”这样的演讲。

2012年12月更新:我已经发布了我的一个新演示:如何设计索引,真的。2012年10月,我在圣克拉拉的ZendCon和12月的伦敦Percona Live上发表了这篇文章。

设计最佳索引的过程必须与你在应用程序中运行的查询相匹配。

很难推荐任何通用规则,比如哪些列最好索引,或者是否应该索引所有列还是不索引列,哪些索引应该跨多个列,等等。这取决于您需要运行的查询。

是的,有一些开销,所以您不应该创建不必要的索引。但是您应该创建索引,以便快速运行所需的查询。索引的开销通常远远超过它的收益。

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

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

请注意,如果您正在搜索可能位于长varchar中间的单词,那么传统的索引就无法提供帮助。为此,使用全文索引。


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

复合指标

您可以创建复合索引—包含多个列的索引。MySQL可以从左到右使用这些。如果你有:

Table A
Id
Name
Category
Age
Description

如果你有一个复合索引,按顺序包含名字/类别/年龄,这些WHERE子句将使用索引:

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

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

but

WHERE Category='A' and Age > 18

不会使用这个索引,因为所有东西都是从左到右使用的。

解释

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

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

慢速查询日志

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

宽栏

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


你绝对应该花一些时间阅读索引,有很多关于它的文章,了解发生了什么很重要。

一般来说,索引对表中的行施加了顺序。

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

假设您将CSV文件加载到一个非常基本的电子表格应用程序中。这个电子表格所做的就是显示数据,并按顺序为行编号。

现在想象一下,您需要找到第三列中值为“M”的所有行。考虑到你所拥有的,你只有一个选择。扫描表,检查每一行的第三列的值。如果有很多行,这种方法(“表扫描”)可能会花费很长时间!

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

现在您有了一个很好的策略,可以找到所有第三列值为“M”的行。例如,您可以执行二分搜索!尽管表扫描需要查看N行(其中N是行数),但在最坏的情况下,二分搜索只需要查看log-n个索引项。哇,那肯定简单多了!

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

因此,一般来说,索引会在读效率和写效率之间做出权衡。在没有索引的情况下,插入可以非常快——数据库引擎只是向表中添加一行。在添加索引时,引擎必须在执行插入操作时更新每个索引。

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

希望这涵盖了你的前两个问题(就像其他人回答的那样——你需要找到正确的平衡)。

第三个场景稍微复杂一些。如果你使用LIKE,索引引擎通常会帮助你将阅读速度提高到第一个“%”。换句话说,如果您正在选择WHERE列,如'foo%bar%',数据库将使用索引来查找列以"foo"开头的所有行,然后需要扫描该中间行集以查找包含"bar"的子集。选择……WHERE '%bar%'这样的列不能使用索引。我希望你能明白原因。

最后,您需要开始考虑多个列上的索引。概念是相同的,行为类似于LIKE的东西——本质上,如果你在(a,b,c)上有一个索引,引擎将继续从左到右尽可能地使用索引。所以在列a上的搜索可能使用(a,b,c)索引,就像在(a,b)上的搜索一样。然而,如果你搜索WHERE b=5 AND c=1,引擎将需要做一个全表扫描。

希望这能帮助您了解一些情况,但我必须重申,您最好花几个小时去挖掘深入解释这些事情的好文章。阅读特定数据库服务器的文档也是一个好主意。查询计划器实现和使用索引的方式可能差别很大。


一般来说,索引有助于加速数据库搜索,缺点是使用额外的磁盘空间和减慢INSERT / UPDATE / DELETE查询。使用EXPLAIN并读取结果,以找出MySQL何时使用您的索引。

如果一个表有六列,他们都是可搜索的,我应该索引他们所有或没有他们?

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

(a)在搜索特定信息时,你会使用这些列吗?

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

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

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

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

如果我有一个varchar2500列,可以从我的网站的部分搜索,我应该索引它吗?

试试FULLTEXT索引。