Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  Multiple-Column Indexes

10.3.6 多列索引

MySQL 可以创建复合索引(即多列索引)。一个索引最多可以包含 16 列。对于某些数据类型,您可以索引列的前缀(请参阅 第 10.3.5 节,“列索引”)。

MySQL 可以使用多列索引来加速测试所有索引列、测试第一个列、测试前两个列、测试前三个列等查询。如果您在索引定义中正确地指定了列的顺序,单个复合索引可以加速同一表上的多种查询。

多列索引可以被认为是一个排序数组,其中的行包含通过连接索引列的值创建的值。

Note

作为复合索引的替代方案,您可以引入一个基于其他列信息的“哈希”列。如果该列很短、相对唯一且索引了,它可能比多列索引更快。在 MySQL 中,使用这个额外的列非常容易:

SELECT * FROM tbl_name
  WHERE hash_col=MD5(CONCAT(val1,val2))
  AND col1=val1 AND col2=val2;

假设一个表具有以下规范:

CREATE TABLE test (
    id         INT NOT NULL,
    last_name  CHAR(30) NOT NULL,
    first_name CHAR(30) NOT NULL,
    PRIMARY KEY (id),
    INDEX name (last_name,first_name)
);

名称索引是一个索引,跨越 last_namefirst_name 列。该索引可以用于在查询中指定 last_namefirst_name 值的已知范围内的查找。它也可以用于仅指定 last_name 值的查询,因为该列是索引的左most 前缀(如本节后面所述)。因此,名称索引用于以下查询:

SELECT * FROM test WHERE last_name='Jones';

SELECT * FROM test
  WHERE last_name='Jones' AND first_name='John';

SELECT * FROM test
  WHERE last_name='Jones'
  AND (first_name='John' OR first_name='Jon');

SELECT * FROM test
  WHERE last_name='Jones'
  AND first_name >='M' AND first_name < 'N';

然而,名称索引 用于以下查询:

SELECT * FROM test WHERE first_name='John';

SELECT * FROM test
  WHERE last_name='Jones' OR first_name='John';

假设您发出以下 SELECT 语句:

SELECT * FROM tbl_name
  WHERE col1=val1 AND col2=val2;

如果存在多列索引在 col1col2 上,适当的行可以直接获取。如果存在单独的单列索引在 col1col2 上,优化器将尝试使用索引合并优化(请参阅 第 10.2.1.3 节,“索引合并优化”),或尝试找到最 restrict 索引,以决定哪个索引排除更多的行并使用该索引来获取行。

如果表具有多列索引,任何左most 前缀索引都可以由优化器用于查找行。例如,如果您有一个三列索引在 (col1, col2, col3) 上,您将拥有 (col1)(col1, col2)(col1, col2, col3) 的索引搜索功能。

MySQL 无法使用索引来执行查找,如果列不形成索引的左most 前缀。假设您有以下 SELECT 语句:

SELECT * FROM tbl_name WHERE col1=val1;
SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;

SELECT * FROM tbl_name WHERE col2=val2;
SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;

如果存在索引在 (col1, col2, col3) 上,只有前两个查询使用索引。第三个和第四个查询涉及索引列,但不使用索引来执行查找,因为 (col2)(col2, col3) 不是 (col1, col2, col3) 的左most 前缀。