您使用的是什么版本的 MySQL?这是我在 Percona Server 5.5.16 上运行的测试:
mysql> create table table_users (
id int auto_increment primary key,
fullname char(20),
username char(20),
unique key (fullname)
);
Query OK, 0 rows affected (0.03 sec)
mysql> insert into table_users values (default, 'billk', 'billk');
Query OK, 1 row affected (0.00 sec)
mysql> explain select * from table_users where fullname='billk'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: table_users
type: const
possible_keys: fullname
key: fullname
key_len: 21
ref: const
rows: 1
Extra:
1 row in set (0.00 sec)
这表明它正在使用全名索引,通过常量值查找,但它不是仅索引查询。
mysql> explain select fullname from table_users where fullname='billk'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: table_users
type: const
possible_keys: fullname
key: fullname
key_len: 21
ref: const
rows: 1
Extra: Using index
1 row in set (0.00 sec)
正如预期的那样,它能够从全名索引中获取全名列,所以这是一个仅索引查询。
mysql> explain select id from table_users where fullname='billk'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: table_users
type: const
possible_keys: fullname
key: fullname
key_len: 21
ref: const
rows: 1
Extra: Using index
1 row in set (0.00 sec)
搜索全名但获取主键也是一个仅索引查询,因为 InnoDB 二级索引的叶子节点(例如唯一键)隐式包含主键值。所以这个查询能够遍历 BTREE 以获取全名,并且作为奖励它也可以获取 id。
mysql> explain select fullname, username from table_users where fullname='billk'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: table_users
type: const
possible_keys: fullname
key: fullname
key_len: 21
ref: const
rows: 1
Extra:
1 row in set (0.00 sec)
只要选择列表包含不属于索引的任何列,它就不能再是仅索引查询。首先它在 BTREE 中搜索 fullname,以找到主键值。然后它使用该 id 值遍历聚集索引的 BTREE,这就是 InnoDB 存储整个表的方式。它在那里找到给定行的其他列,包括用户名。