MySQL 可以创建组合索引(即,对多个列进行索引)。索引最多可以包含 16 列。对于某些数据类型,您可以对列的前缀进行索引(请参见 第 10.3.5 节,“列索引”)。
MySQL 可以对测试索引中所有列的查询或只测试第一列、前两列、前三列等的查询使用多列索引。如果您在索引定义中按正确顺序指定列,则单个组合索引可以加速对同一表上的多种查询。
可以将多列索引视为一个排序数组,该数组的行包含通过连接索引列的值创建的值。
作为组合索引的替代方案,您可以引入一个基于其他列信息进行“哈希”的列。如果此列很短,比较独特且已索引,它可能比对许多列的“宽”索引更快。在 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_name
和 first_name
列的索引。该索引可用于在指定 last_name
和 first_name
值组合的已知范围内的查询中进行查找。它也可用于仅指定 last_name
值的查询,因为该列是索引的最左侧前缀(如本节稍后所述)。因此,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;
如果 col1
和 col2
上存在多列索引,则可以直接获取相应的行。如果 col1
和 col2
上存在单独的单列索引,则优化器尝试使用索引合并优化(请参见 第 10.2.1.3 节,“索引合并优化”),或者尝试通过确定哪一个索引排除了更多行来找到最严格的索引,并使用该索引来获取行。
如果表具有多列索引,则优化器可以使用索引的最左侧前缀来查找行。例如,如果您在 (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)
的最左侧前缀。