索引用于快速找到具有特定列值的行。没有索引,MySQL 必须从第一行开始,然后读取整个表以找到相关行。表越大,这个成本越高。如果表具有相关列的索引,MySQL 可以快速确定数据文件中的位置,而不需要查看所有数据。这比顺序读取每一行要快得多。
大多数 MySQL 索引 (PRIMARY KEY
、UNIQUE
、INDEX
和 FULLTEXT
) 都存储在 B 树 中。例外:空间数据类型的索引使用 R 树;MEMORY
表也支持 哈希索引;InnoDB
使用反转列表来存储 FULLTEXT
索引。
一般来说,索引按照以下讨论所述使用。哈希索引(如在 MEMORY
表中使用)特征在 第 10.3.9 节,“B 树和哈希索引的比较” 中描述。
MySQL 使用索引来执行以下操作:
-
快速找到与
WHERE
子句匹配的行。 -
排除行以减少考虑的行数。如果有多个索引可供选择,MySQL 通常使用找到最少行数的索引(最 选择性 的索引)。
-
如果表具有多列索引,任何左侧前缀索引都可以由优化器用于查找行。例如,如果您有一个三列索引
(col1, col2, col3)
,那么您在(col1)
、(col1, col2)
和(col1, col2, col3)
上都有索引搜索功能。有关更多信息,请参阅 第 10.3.6 节,“多列索引”。 -
在执行连接时,从其他表中检索行。MySQL 可以更高效地使用索引,如果它们被声明为相同的类型和大小。在这个上下文中,
VARCHAR
和CHAR
被认为是相同的大小。例如,VARCHAR(10)
和CHAR(10)
是相同的大小,但VARCHAR(10)
和CHAR(15)
不是。对于非二进制字符串列的比较,两个列都应该使用相同的字符集。例如,比较
utf8mb4
列与latin1
列将阻止使用索引。比较不同类型的列(例如比较字符串列与时间或数字列)可能会阻止使用索引,如果值不能直接比较而不需要转换。例如,对于数字列中的特定值
1
,它可能与字符串列中的多个值相等,例如'1'
、' 1'
、'00001'
或'01.e1'
。这排除了字符串列的索引使用。 -
找到特定索引列
key_col
的MIN()
或MAX()
值。这通过预处理器来优化,该预处理器检查您是否使用WHERE
在所有 key 部分中,该部分出现在索引中的key_part_N
=constant
key_col
之前。在这种情况下,MySQL 对每个MIN()
或MAX()
表达式执行单个键查找,并将其替换为常量。如果所有表达式都被替换为常量,查询将立即返回。例如:SELECT MIN(key_part2),MAX(key_part2) FROM tbl_name WHERE key_part1=10;
-
如果对表进行排序或分组,并且排序或分组是基于可用索引的左most前缀(例如,
ORDER BY
)。如果所有键部分都跟随key_part1
,key_part2
DESC
,则键将以逆序读取。(或者,如果索引是降序索引,键将以正序读取。)请参阅 第 10.2.1.16 节,“ORDER BY 优化”、第 10.2.1.17 节,“GROUP BY 优化” 和 第 10.3.13 节,“降序索引”。 -
在某些情况下,查询可以被优化以从不consult数据行中检索值。(提供所有必要结果的索引称为 覆盖索引。)如果查询仅从表中使用某些列,而这些列都包含在某个索引中,那么可以从索引树中检索所需值,以提高速度:
SELECT key_part3 FROM tbl_name WHERE key_part1=1
对于小表或大表中的报告查询处理大多数或所有行,索引变得不那么重要。当查询需要访问大多数行时,顺序读取比通过索引工作更快。顺序读取可以最小化磁盘寻道,即使查询不需要所有行。请参阅 第 10.2.1.23 节,“避免全表扫描” 了解详情。