# 5.5 多列索引

MySQL可以创建复合索引（即，多列上的索引）。一个索引最多可以包含16列。对于某些数据类型，您可以为列的前缀编制索引

MySQL可以将多列索引用于测试索引中所有列的查询，或者仅测试第一列，前两列，前三列等等的查询。如果按正确的顺序在索引定义中指定列，则单个复合索引可以加快对同一表的几种查询。

多列索引可以被认为是排序数组，其行包含通过串联索引列的值而创建的值。

> 注意
>
> 作为复合索引的替代方法，您可以根据其他列中的信息引入一个被“ 哈希化 ”的列。如果此列短，合理地唯一且已建立索引， 则它可能比许多列上的“ 宽 ”索引快。在MySQL中，使用此额外的列非常容易：

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

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

```sql
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_name`和`first_name` 列。该索引可用于查询中的查找，这些查询指定在已知范围内的`last_name`和`first_name` 值组合的 值。它也可以用于仅指定`last_name`值的查询， 因为该列是索引的最左前缀（如本节稍后所述）。因此，该`name`索引用于以下查询中的查找：

```sql
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`索引 _&#x4E0D;_&#x7528;于查找：

```sql
SELECT * FROM test WHERE first_name='John';

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

假设您发出以下 `SELECT`语句：

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

如果col1和上 存在多列索引col2，则可以直接获取相应的行。如果col1和上存在单独的单列索引 col2，那么优化器将尝试使用索引合并优化， 或者尝试通过确定哪个索引排除更多行并使用来查找限制性最强的索引。该索引以获取行。

如果表具有多列索引，那么优化器可以使用索引的任何最左前缀来查找行。 举例来说，如果你有一个三列的索引(col1, col2, col3)，你有索引的搜索功能 (col1)，(col1, col2)以及 (col1, col2, col3)。

如果列不构成索引的最左前缀，则MySQL无法使用索引执行查找。假设您具有以下SELECT所示的语句：

```sql
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)`。
