Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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

10.3.6 多列索引

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

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)
);

索引name是对last_名first_名列的索引。该索引可以用于查询指定已知范围的组合值的查找,包括last_名first_名值。它也可以用于查询只指定last_名值,因为该列是索引的左前缀(后续部分将详细描述)。因此,索引name用于以下查询:

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';

然而,索引name不用于以下查询:

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中,优化器尝试使用Index Merge优化(见第10.2.1.3节,“Index Merge Optimization”),或尝试找到最具约束的索引,通过决定哪个索引排除更多行并使用该索引获取行。

如果表具有多列索引,可以由优化器使用索引的任何左前缀来查找行。例如,如果您有一个三列索引(col1, col2, col3),您就拥有了对(col1)(col1, col2)(col1, col2, col3)的索引搜索能力。

MySQL 无法使用索引来执行查找操作,如果列不构成索引的左前缀。假设您有以下所示的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) 的左前缀。