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

我已经在我的MySQL数据库上使用了一段时间的索引了,但是从来没有正确地过这些索引。 一般来说,我会在任何我将要使用WHERE子句进行search或select的字段上放置一个索引,但是有时它看起来并不那么黑白。

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

示例情况/难题:

如果一个表有六列,而且所有这些列都是可search的,那么我应该把它们全部或全部都编入索引吗?

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

如果我有一个VARCHAR 2500列可以从我的网站的部分search,我应该索引它?

你一定要花一些时间阅读索引,写了很多关于它的知识,了解发生了什么很重要。

广义地说,索引对表的行进行sorting。

为了简单起见,想象一下,表格只是一个很大的CSV文件。 无论何时插入一行,它都插入到最后 。 所以表的“自然”顺序就是插入行的顺序。

想象一下,你已经将这个CSV文件加载到一个非常基本的电子表格应用程序中。 所有这些电子表格都会显示数据,并按顺序对行进行编号。

现在想象一下,你需要在第三列中find所有具有“M”值的行。 鉴于你有什么可用的,你只有一个选项。 您扫描表检查每行的第三列的值。 如果你有很多行,这种方法(“表扫描”)可能需要很长时间!

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

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

当然,如果你有这个索引,并且你正在向表中添加行(最后,因为这是我们的概念表的工作原理),你需要每次更新索引。 所以当你写新的行的时候,你会做更多的工作,但是当你search某些东西的时候,你可以节省大量的时间。

因此,一般来说,索引build立了读取效率和写入效率之间的折衷。 没有索引,插入可以非常快 – 数据库引擎只是在表中添加一行。 在添加索引时,引擎必须在执行插入时更新每个索引。

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

希望能涵盖你的前两个问题(正如其他人所回答的 – 你需要find合适的平衡点)。

你的第三种情况有点复杂。 如果您使用的是LIKE,索引引擎通常会帮助您将读取速度提高到第一个“%”。 换句话说,如果SELECTing WHERE列LIKE'foo%bar%',数据库将使用索引来查找列以“foo”开头的所有行,然后需要扫描该中间行集以查找子集包含“酒吧”。 SELECT … WHERE列LIKE'%bar%'不能使用索引。 我希望你能明白为什么。

最后,你需要开始考虑多个列的索引。 这个概念是相同的,其行为与LIKE类似 – essentialy,如果你有(a,b,c)上的索引,引擎会尽可能从左到右继续使用索引。 因此,对列a的search可以使用(a,b,c)索引,就像(a,b)上的那样。 但是,如果您正在searchWHERE b = 5且c = 1,则引擎需要执行全表扫描)

希望这有助于解决一些小问题,但是我必须重申,最好花几个小时的时间来挖掘好的文章来深入解释这些问题。 阅读特定数据库服务器的文档也是一个好主意。 查询计划人员实施和使用索引的方式差别很大。

看看更多掌握索引艺术的演示文稿。

更新12/2012:我已经发布了我的新演示文稿: 如何devise索引,真的 。 我于2012年10月在圣克拉拉的ZendCon展会上展出了这款产品,并于2012年12月在Percona Live London上展出了这款产品。

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

很难推荐关于哪些列最适合索引的通用规则,或者应该索引所有列,没有列,哪些索引应该跨越多个列等。这取决于您需要运行的查询。

是的,有一些开销,所以你不应该不必要地创build索引。 但是,您应该创build索引,以便为需要快速运行的查询提供帮助。 指数的开销通常远远超过其收益。

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

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

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

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

复合指数

您可以创build复合索引 – 包含多个列的索引。 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可用的索引和它实际select的索引。 MySQL将只使用每个查询一个

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

慢查询日志

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

宽列

如果您有一个宽的列,其中最前面的几个字符发生了最多的区分,那么您只能使用索引中的前N个字符。 示例:我们有一个定义为varchar(255)的ReferenceNumber列,但97%的情况下,引用数字是10个字符或更less。 我改变了索引只看前10个字符,提高了性能不less。

如果一个表有六列,并且所有这些列都是可search的,那么我应该把它们全部索引还是全部索引

你是在字段的基础上search还是使用多个字段进行一些search? 哪些字段被search? 什么是字段types? (例如,索引在INT上比在VARCHAR上更好)您是否尝试在正在运行的查询上使用EXPLAIN?

索引的性能影响是什么?

UPDATE和INSERT将会变慢。 还有额外的存储空间需求,但这些通常是不重要的这些天。

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

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

一般来说,我把任何领域,我将search或使用WHERE子句select索引

我通常索引最多查询的字段,然后INTs / BOOLEANs / ENUMs,而不是字段是VARCHARS。 不要忘记,通常您需要在组合字段上创build索引,而不是在单个字段上的索引。 使用EXPLAIN,并检查慢日志。

有效加载数据 :索引加快了检索速度,但减慢了插入和删除操作,以及更新索引列中的值。 也就是说,索引减缓了涉及编写的大部分操作。 发生这种情况是因为写一行不仅需要写入数据行,还需要更改任何索引。 表格的索引越多,需要进行的更改越多,平均性能下降越大。 大多数表获得很多读取和很less的写入,但是对于具有高写入百分比的表而言,索引更新的成本可能是显着的。

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

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

外卖:不要超过指数

一般来说,索引有助于加快数据库search速度,具有使用额外磁盘空间和减慢INSERT / UPDATE / DELETE查询的缺点。 使用EXPLAIN并阅读结果来了解MySQL何时使用您的索引。

如果一个表有六列,而且所有这些列都是可search的,那么我应该把它们全部还是全都编入索引?

索引所有六栏并不总是最好的做法。

(a)在search特定信息时是否要使用这些列?

(b)这些列的select性是多less(与表中logging的总数相比,存储了多less不同的值)?

MySQL使用基于成本的优化器,在执行查询时试图find“最便宜”的path。 而select性低的领域是不适合的。

索引的性能影响是什么?

已经回答:额外的磁盘空间,插入时更低的性能 – 更新 – 删除。

如果我有一个VARCHAR 2500列可以从我的网站的部分search,我应该索引它?

试试FULLTEXT索引 。

1/2)索引加速某些select操作,但是会减慢插入,更新和删除等操作。 它可以是一个很好的平衡。

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