索引用于快速查找具有特定列值的记录。如果没有索引,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()
值。这通过预处理器进行了优化,该预处理器会检查您是否在索引中key_col
之前的 所有键部分上使用了WHERE
。在这种情况下,MySQL 对每个key_part_N
=constant
MIN()
或MAX()
表达式执行一次键查找,并将其替换为常量。如果所有表达式都被替换为常量,则查询会立即返回结果。例如:SELECT MIN(key_part2),MAX(key_part2) FROM tbl_name WHERE key_part1=10;
如果排序或分组是在可用索引的最左侧前缀上完成的(例如,
ORDER BY
),则对表进行排序或分组。如果所有键部分后都跟有key_part1
,key_part2
DESC
,则按相反顺序读取键。(或者,如果索引是降序索引,则按顺序读取键。)请参阅第 10.2.1.16 节“ORDER BY 优化”、第 10.2.1.17 节“GROUP BY 优化”和第 10.3.13 节“降序索引”。在某些情况下,可以优化查询以检索值,而无需查阅数据行。(为查询提供所有必要结果的索引称为覆盖索引。)如果查询仅使用表中包含在某个索引中的列,则可以从索引树中检索选定的值,以提高速度。
SELECT key_part3 FROM tbl_name WHERE key_part1=1
对于小型表或大型表(其中报表查询处理大部分或所有行)的查询,索引不太重要。当查询需要访问大部分行时,顺序读取比通过索引工作更快。顺序读取最大限度地减少了磁盘查找,即使并非所有行都需要用于查询。有关详细信息,请参阅第 10.2.1.23 节“避免全表扫描”。