MySQL 索引 - 最佳实践是啥?

Posted

技术标签:

【中文标题】MySQL 索引 - 最佳实践是啥?【英文标题】:MySQL indexes - what are the best practices?MySQL 索引 - 最佳实践是什么? 【发布时间】:2010-06-15 21:39:07 【问题描述】:

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

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

示例情况/困境:

如果一个表有六列并且所有列都可搜索,我应该对所有列都编制索引还是不编制索引?

索引对性能有哪些负面影响?

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

【问题讨论】:

您可能应该重新标记问题。索引的选择是优化任何数据库模型的重要部分。在我看来与 php 无关。 dev.mysql.com/doc/refman/5.5/en/mysql-indexes.html ***.com/q/3567981/3404097 【参考方案1】:

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

从广义上讲,索引对表的行进行排序。

为简单起见,假设一个表只是一个大的 CSV 文件。每当插入一行时,它就会插入在末尾​​em>。所以表格的“自然”顺序就是插入行的顺序。

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

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

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

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

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

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

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

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

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

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

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

【讨论】:

FULLTEXT 索引呢?他们可以帮助解决LIKE '%bar%' 之类的情况吗? @Septagram - FULLTEXT 可以帮助 that 查询 if bar 是一个“单词”。 FULLTEXT 处理单词,而不是任意子字符串(就像 LIKE 那样)。 @timdev 明确回答了第一个问题的哪一部分?我可以检测到您宝贵答案的第一部分和第二部分(希望涵盖您的前两个问题之前和之后)回答的第二个和第三个问题 @ManuelJordan - 第一个问题没有简单的答案。这取决于您希望如何在预期(甚至更好,观察到的)使用情况下平衡权衡。 一篇关于 MySQL 索引最佳实践的文章。 medium.com/@akhilmathew_/…【参考方案2】:

查看类似More Mastering the Art of Indexing 的演示文稿。

12/2012 更新:我发布了我的新演示文稿:How to Design Indexes, Really。我于 2012 年 10 月在圣克拉拉的 ZendCon 和 2012 年 12 月的 Percona Live London 上展示了这个。

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

很难推荐任何通用规则来确定哪些列最适合建立索引,或者是否应该索引所有列、没有列、哪些索引应该跨越多个列等等。这取决于您需要运行的查询。

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

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

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

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

【讨论】:

非常感谢。 slideshare.net/matsunobu/… 确实很有帮助。 slideshare.net/billkarwin/how-to-design-indexes-really slideshare.net/matsunobu/… 两个链接都不起作用 出色的slideshare.net/billkarwin/how-to-design-indexes-really 演示文稿【参考方案3】:

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

复合指数

您可以创建复合索引 - 包含多列的索引。 MySQL 可以从 leftright 使用这些。所以如果你有:

Table A
Id
Name
Category
Age
Description

如果您的复合索引按该顺序包含名称/类别/年龄,则这些 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 每个查询只使用 ONE

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

慢查询日志

打开slow query log 以查看哪些查询运行缓慢。

宽栏

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

【讨论】:

我对最后一部分有疑问。我在某处读到,如果您使用 VARCHAR 创建列,则应始终将其设置为 255。现在您说设置为此类列的索引可能仅限于查看前 10 个字符。你到底是怎么做到的? @AlexioVay 以col_name(N) 的形式使用Index Prefixes。【参考方案4】:

如果一个表有六列并且所有列都是可搜索的,我应该索引所有列还是一个都不索引

您是逐个字段进行搜索,还是使用多个字段进行一些搜索? 哪些字段被搜索? 字段类型有哪些? (例如,索引在 INT 上比在 VARCHAR 上效果更好) 您是否尝试过对正在运行的查询使用 EXPLAIN?

索引对性能有哪些负面影响

UPDATE 和 INSERT 会更慢。还有额外的存储空间要求,但现在这通常不重要。

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

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

通常我会使用 WHERE 子句在我将要搜索或选择的任何字段上放置一个索引

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

【讨论】:

【参考方案5】:

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

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

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

要点:不要过度索引

【讨论】:

【参考方案6】:

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

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

索引所有六列并不总是最佳做法。

(a) 您在搜索特定信息时是否会使用这些列中的任何一个?

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

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

索引对性能有哪些负面影响?

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

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

试试FULLTEXT Index。

【讨论】:

【参考方案7】:

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

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

【讨论】:

为了防止slow down other operations like insert, update and deletes,您可以使用START TRANSACTION; YOUR CODE HERE; COMMIT 这可以帮助避免slowing down 其他操作,因为它一次只会检查一个约束。警告:如果您使用 REPLACE INTOSQL_MODE STRICT_ALL_TABLESTRADITIONAL Bulk Load 将忽略替换并插入重复项。 并非所有 MySQL 引擎都支持事务。 AFAIK,事务会减慢数据库操作,即使它们仅被隐式使用。我们需要根据实际性能设计的是一些半自动的方式来分析(衡量性能)各种优化选择,包括索引和事务。

以上是关于MySQL 索引 - 最佳实践是啥?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 索引最佳实践

Mysql 索引:查询生成器的最佳实践

MySQL性能优化的21个最佳实践 和 mysql使用索引

MySQL性能优化的21个最佳实践 和 mysql使用索引

ySQL性能优化的21个最佳实践 和 mysql使用索引

索引最佳实践