索引用于快速查找具有特定列值的记录行。如果没有索引,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 节 “避免全表扫描”。