美文网首页
mysql查询到底用了组合索引的哪些字段

mysql查询到底用了组合索引的哪些字段

作者: binecy | 来源:发表于2018-12-23 17:13 被阅读39次

工作中,我们常常使用到mysql的组合索引,但怎样判断mysql查询时,使用了组合索引的那些字段呢?
最近从我司DBA中学了一招,就是结合explain的key_len(索引长度字节数)和组合索引索引的字段长度来判断。

首先,我定义一个任务表

create table `my_task`(
`id` bigint unsigned not null auto_increment comment '任务id',
`task_type` varchar(32) not null comment '任务类型 1-待执行,2-执行中 3-执行成功 4-执行失败',
`server_id` char(16) comment '处理节点ip',
`process_status` int unsigned not null comment '处理状态',
`process_time` timestamp not null comment '处理时间',
`create_time`  timestamp default current_timestamp comment '创建时间',
`update_time`  timestamp default current_timestamp on update current_timestamp  comment '更新时间',
primary key (`id`),
key `key_task_type` (`task_type`) ,
key `key_server_id` (`server_id`),
key `key_process_status`(`process_status`),
key `key_process_time` (`process_time`),
key `key_multiple` (`task_type`,`server_id`, `process_status`, `process_time`)
) engine=innodb default charset=utf8;

我定义了很多索引,方便后面实例分析。

  1. 找出所有的下载任务:
mysql> explain select * from my_task where task_type = 'download';
+----+-------------+---------+------------+------+----------------------------+---------------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys              | key           | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+----------------------------+---------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | my_task | NULL       | ref  | key_task_type,key_multiple | key_task_type | 98      | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+------+----------------------------+---------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

使用了key_task_type索引,该索引建立在task_type varchar(32) 字段上。
varchar(32)表示32个字符,utf8编码下一个字符有3个字节,另外varchar还需要两个字节作为长度标示,所以explain的key_len为32*3 + 2 = 98

  1. 找出本地执行的任务:
mysql> explain select * from my_task where server_id = '127.0.0.1';
+----+-------------+---------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key           | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | my_task | NULL       | ref  | key_server_id | key_server_id | 49      | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

使用了key_server_id 索引,对应于server_id char(16)字段,另外,server_id允许为null,所以还需要一个字节表示是否为null,所以explain的key_len为16*3+1=49

  1. 找出待执行的任务:
mysql> explain select * from my_task  where process_status = 1;
+----+-------------+---------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys      | key                | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | my_task | NULL       | ref  | key_process_status | key_process_status | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

比较简单,使用了key_process_status索引,对应的process_status int 为4个字节。

  1. 找出2018-08-09后执行的任务:
mysql> explain select * from my_task where process_time >= '2018-08-09';
+----+-------------+---------+------------+-------+------------------+------------------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys    | key              | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+------------------+------------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | my_task | NULL       | range | key_process_time | key_process_time | 4       | NULL |    1 |   100.00 | Using index condition |
+----+-------------+---------+------------+-------+------------------+------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

简单,使用了key_process_time 索引,对应process_time timestamp字段也是4个字节。

  1. 找出2018-08-09后本机执行的下载任务:
mysql> explain select * from my_task force  index(key_multiple) where task_type = 'download' and server_id = '127.0.0.1' and process_time >= '2018-08-09';
+----+-------------+---------+------------+------+---------------+--------------+---------+-------------+------+----------+-----------------------+
| id | select_type | table   | partitions | type | possible_keys | key          | key_len | ref         | rows | filtered | Extra                 |
+----+-------------+---------+------------+------+---------------+--------------+---------+-------------+------+----------+-----------------------+
|  1 | SIMPLE      | my_task | NULL       | ref  | key_multiple  | key_multiple | 147     | const,const |    1 |   100.00 | Using index condition |
+----+-------------+---------+------------+------+---------------+--------------+---------+-------------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

为了方便分析,这里使用了force index强制使用key_multiple(task_type,server_id, process_status, process_time)索引。
key_len为147,等于(32*3+2) + (16*3+1),而32*3+2为task_type字段长度,16*3+1为server_id字段长度,可以看出,查询条件process_time 无法使用索引,这也是符合最左匹配原则的。

  1. 找出2018-08-09后本机执行成功或者失败的下载任务:
mysql> explain select * from my_task force  index(key_multiple) where task_type = 'download' and server_id = '127.0.0.1' and process_status in (3,4) and  process_time >= '2018-08-09';
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | my_task | NULL       | range | key_multiple  | key_multiple | 155     | NULL |    2 |   100.00 | Using index condition |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

key_len为155,等于(32*3+2) + (16*3+1) + 4 + 4,可以看到该查询使用了key_multiple的所有字段。
看来索引中间字段(process_status)使用了in条件,也不妨碍后面字段(process_time)使用索引。

  1. 找出2018-08-09后被本机执行的下载任务:
mysql> explain select * from my_task force  index(key_multiple) where task_type = 'download' and server_id = '127.0.0.1' and process_status > 1 and  process_time >= '2018-08-09';
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | my_task | NULL       | range | key_multiple  | key_multiple | 151     | NULL |    1 |   100.00 | Using index condition |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

key_len为151,等于(32*3+2) + (16*3+1) + 4,这里process_status > 1使用了范围查询,所以后面的字段process_time不能使用索引了。但process_status是可以使用索引的。

  1. 找出2018-08-09后处理节点不为null的待处理下载任务(这种是异常任务):
mysql> explain select * from my_task force  index(key_multiple) where task_type = 'download' and server_id is null and process_status = 1 and  process_time >= '2018-08-09';
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | my_task | NULL       | range | key_multiple  | key_multiple | 155     | NULL |    1 |   100.00 | Using index condition |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.01 sec)

key_len为155,就是key_multiple所有字段都使用了索引,看来,查询为null的server_id字段不会影响后面字段使用索引,只是索引需要使用一个额外字节标示字段是否为null。

很实用的技巧,感谢我司DBA。

参考:
B+树实现范围查询
MYSQL EXPLAIN 中的KEY_LEN的说明
8.8.2 EXPLAIN Output Format
11.4.1 The CHAR and VARCHAR Types

相关文章

  • mysql查询到底用了组合索引的哪些字段

    工作中,我们常常使用到mysql的组合索引,但怎样判断mysql查询时,使用了组合索引的那些字段呢?最近从我司DB...

  • 关于数据库一些面试总结

    1.怎么查看该字段是否使用了索引,索引的作用,什么情况下(哪些字段可以)使用索引,索引的类型? (1)mysql可...

  • mysql 知识点汇总

    1. 使用 mysql 索引都有哪些原则? 只对WHERE和ORDER BY需要查询的字段设置索引,避免无意义的硬...

  • 索引的技术点

    联合索引:多字段组合索引,加速组合条件查询 联合索引要满足从左到右的查询需求,例如(a,b,c)的联合索引,能够加...

  • 为何MySQL会选错索引

    在实际的生产环境中,给MySQL的字段加索引让查询的效率更高,我们往往会给MySQL的表字段加索引。MySQL具体...

  • MySQL索引失效

    哪些情况需要创建索引 主键自动建立唯一索引频繁作为查询条件的字段应该创建索引多表关联查询中,关联字段应该创建索引 ...

  • mongo组合索引中使用时间字段的注意事项

    最近项目中有一个查询需要用到添加时间字段和区域字段的组合查询,发现把时间字段放到组合索引的前面和后面,查询效率相差...

  • MySQL索引进阶

    组合索引 常见误区: 表上建多个索引,就是组合索引(不是);组合索引创建时应该把整数字段放前面(要根据查询情况而定...

  • (转载)联合索引优化多条件查询

    转载自:联合索引优化多条件查询 联合索引是由多个字段组成的组合索引。若经常需要使用多个字段的多条件查询(WHERE...

  • MySQL索引优化

    trace工具 MySQL执行的跟踪工具,通过trace可以查询sql语句具体使用中使用了哪些索引以及索引的性能比...

网友评论

      本文标题:mysql查询到底用了组合索引的哪些字段

      本文链接:https://www.haomeiwen.com/subject/wsweqqtx.html