假设在tableX中,我们有id(主键)nameage,phone,它们都有索引.

在此查询中: select phone from tableX where name='Dennis' order by age

我想这个过程是

  1. 使用name索引获取与Dennis匹配的ID.用S表示ID集合

  2. 使用age索引对1中获得的ID执行ORDER BY,得到一个排序的ID列表,用L表示

  3. 使用已排序的ID列表L来获取phone

我假设在步骤2中,它可以使用沿着B+树叶 node 的顺序扫描,判断该叶 node 中的id是否在步骤1中获得的id集合S中.如果是,将其添加到列表L中,那么我们可以得到按age排序的id列表L.

但这怎么会比简单的顺序扫描更好呢?它们不都是顺序扫描吗?


编辑:

explain表示它使用索引name,并执行filesort

+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+----------------+
| id | select_type | table  | partitions | type | possible_keys | key      | key_len | ref   | rows | filtered | Extra          |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+----------------+
|  1 | SIMPLE      | tableX | NULL       | ref  | idx_name      | idx_name | 123     | const |    1 |   100.00 | Using filesort |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+----------------+

其实我并不确定什么情况指数在order by条款中是有用的,所以我举了一个不好的例子来说明我的怀疑.

但蒂姆·比格莱森提供的例子很好.


(如果您有兴趣,请查看更多表格详细信息:)

mysql> create table tableX(
    -> id int primary key,
    -> name varchar(30),
    -> age int,
    -> phone varchar(30)
    -> );
Query OK, 0 rows affected (0.07 sec)

mysql> create index idx_name on tableX(name);
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> create index idx_age on tableX(age);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> create index idx_phone on tableX(phone);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from tableX;
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table  | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| tableX |          0 | PRIMARY   |            1 | id          | A         |           1 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| tableX |          1 | idx_name  |            1 | name        | A         |           1 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| tableX |          1 | idx_age   |            1 | age         | A         |           1 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| tableX |          1 | idx_phone |            1 | phone       | A         |           1 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
4 rows in set (0.01 sec)

mysql> select * from tableX;
+----+--------+------+-------+
| id | name   | age  | phone |
+----+--------+------+-------+
|  1 | Jack   |   20 | 180   |
|  2 | Dennis |   22 | 180   |
|  3 | Dennis |   18 | 1790  |
+----+--------+------+-------+

推荐答案

实际上,这里应该有帮助的索引是一个复合索引:

CREATE INDEX idx ON tableX (name, age, phone)

如果使用上述索引,可能会有以下步骤:

  • 可以搜索B树来搜索丹尼斯的名字记录.
  • 一旦找到了B树的那个区域,记录就会按年龄进行排序
  • 可以执行扫描以使用按年龄排序的Dennis记录填充结果集
  • 索引还包括phone列,这使查询的值为covering index;它需要的所有列都可以直接从索引中读取.

Mysql相关问答推荐

MySQL InnoDB:可以在没有回滚损失的情况下从运行的查询中进行大型插入吗

在MySQL中从非连续数据创建时间线

我需要为用户提供MySQL视图和存储的 routine ,但不是基础表

优化使用ORDER BY加载耗时较长的MySQL请求

基于多行从表中 Select

如何合并有多行的json列

表列中的SQL SUM MENY值记录单个查询

MySQL中如何对字符串进行算术运算?

从 NextJS/Prisma 添加用户 ID (FK) 到 MySQL 表

在MySQL查询中查找和替换表内的值

为什么我的 SQL 查询不更新 Node.js 和 MySQL 中用户以外的用户属性?

MySQL Procedure 变量在 count(*) 上接收 null

go&mysql&docker 拒绝连接

为什么 fetch 方法不能获取任何东西?(feat node.js,restAPI)

为什么从我的 SQL 查询中删除 BINARY 函数调用会如此显着地改变查询计划?

FreeBASIC 中的 MySQL 访问读取

结果差异(MySQL 5.7 vs MySQL 8.0)

在 MySQL 中找不到 outfile 创建的文件

如何计算表格的列数

与 MySql 的连接正在自动中止.如何正确配置Connector/J?