相似的SQL执行计划key_len为什么不同

简介: 相似的SQL执行计划key_len为什么不同

导读

执行计划中看到key_len值发生变化,表示联合索引有时能用到多个列,有时却只能用到部分列,这是为啥子呢?

我的朋友小明同学这几天又遇到一件令人懵*的事,有个SQL执行计划看起来挺诡异的,我看了下,也是有点发懵。

基本信息

严格遵循我自己要求的“提问的艺术”,先交代下必要的背景信息。

1、表DDL(建议手机横过来观看)

[root@yejr.me]>show create table t_keylen\G
*************************** 1. row ***************************
       Table: t_keylen
Create Table: CREATE TABLE `t_keylen` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `userid` bigint(20) unsigned NOT NULL DEFAULT '0',
  `balance` int(10) unsigned NOT NULL DEFAULT '0',
  `type` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `fullName` json NOT NULL,
  PRIMARY KEY (`id`),
  KEY `i_userid_balance` (`userid`,`balance`)
) ENGINE=InnoDB AUTO_INCREMENT=19;

[root@yejr.me]>select * from t_keylen;
+----+--------+---------+------+-----------------------------------------------------------------+
| id | userid | balance | type | fullName                                                        |
+----+--------+---------+------+-----------------------------------------------------------------+
|  1 |      1 |     121 |    1 | {"lastName": "1", "firstName": "fn", "middleName": "mn"}        |
|  2 |      2 |    1236 |    0 | {}                                                              |
|  3 |      3 |     100 |    0 | {"lastName": "3"}                                               |
|  4 |      4 |       5 |    0 | {"lastName": "4", "firstName": "fn"}                            |
|  6 |      5 |      11 |    0 | {"lastName": "ln", "firstName": "fn", "middleName": "mn"}       |
|  7 |      6 |       5 |    0 | {"lastName": "ln", "firstName": "fn", "middleName": "mn"}       |
|  9 |      7 |       5 |    0 | {"lastName": "ln", "firstName": "fn", "middleName": "mn"}       |
| 10 |      8 |       5 |    0 | {"lastName": "ln", "firstName": "fn", "middleName": "mn"}       |
| 11 |     11 |      11 |    0 | {"lastName": "ln", "firstName": "fn", "middleName": "mn"}       |
| 13 |     10 |      11 |    1 | {"lastName": "ln", "firstName": "fn", "middleName": "mn"}       |
| 15 |     14 |      47 |    1 | {"lastName": "wqQSi", "firstName": "U1lc", "middleName": "ijK"} |
| 18 |     12 |       2 |    1 | {"lastName": "K196J", "firstName": "4Uf3", "middleName": "Vlt"} |
+----+--------+---------+------+-----------------------------------------------------------------+
12 rows in set (0.00 sec)

2、索引统计信息(有些输出不影响本案例判断,我给去掉了,建议手机横过来观看)


注意到 i_userid_balance 是一个联合索引,由两列构成,数据类型分别是 bigint 和 int,如果整个索引都被用上的话,其key_len值为12,如果只用到了userid列,则其key_len值为8。

[root@yejr.me]>show index from t_keylen;

+------------+------------------+--------------+-------------+-------------+
| Non_unique | Key_name | Seq_in_index | Column_name | Cardinality |
+------------+------------------+--------------+-------------+-------------+
| 0 | PRIMARY | 1 | id | 12 |
| 1 | i_userid_balance | 1 | userid | 12 |
| 1 | i_userid_balance | 2 | balance | 12 |
+------------+------------------+--------------+-------------+-------------+

3、查看SQL执行计划

先看第一条SQL的执行计划(建议手机横过来观看)

[root@yejr.me]>desc select * from t_keylen where
userid > 10 and balance > 1\G
1. row **
id: 1
select_type: SIMPLE
table: t_keylen
partitions: NULL
type: range
possible_keys: i_userid_balance
key: i_userid_balance
key_len: 8
ref: NULL
rows: 3
filtered: 33.33
Extra: Using index condition

在本例中,key_len值为8,说明联合索引只用到了 userid 列,因为条件 userid > 10 是范围查询,看起来没毛病。

再看第二条SQL(建议手机横过来观看)

[root@yejr.me]>desc select * from t_keylen where
userid >= 10 and balance > 1\G
1. row **
id: 1
select_type: SIMPLE
table: t_keylen
partitions: NULL
type: range
possible_keys: i_userid_balance
key: i_userid_balance
key_len: 12
ref: NULL
rows: 4
filtered: 33.33
Extra: Using index condition

这个结果就有点出乎意料了,不是说联合索引里,如果有一列开始是范围查询的话,那么从它后面的列都用不到索引了,但在本例中,我们看到的是 key_len=12,说明两个列还是都用上了,这是为啥呢?

4、解惑

请教了下知数堂《SQL优化》班的松华老师,终于解惑了。

原来对于数字型的联合索引,最左边的列的是否有等号非常重要,直接决定key_len的大小。本例中是 >= 和> 这种 左列包含等号 的条件,索引长度就可以计算到第二个列。如果是 > 和 > 这种条件,因为最左边的列不包含等号所以只能用到第一个。同理,下面案例是 <=和= 那就key_len值算到第二个列,即其值为12。(建议手机横过来观看)

[root@yejr.me]>desc select * from t_keylen where
userid <= 10 and balance = 1\G
1. row **
...
type: range
possible_keys: i_userid_balance
key: i_userid_balance
key_len: 12
...

好吧,又涨姿势了。

            </div>
相关文章
|
9月前
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(07) 她气鼓鼓递来一条SQL | 怎么看执行计划、SQL怎么优化?
在日常研发工作当中,系统性能优化,从大的方面来看主要涉及基础平台优化、业务系统性能优化、数据库优化。面对数据库优化,除了DBA在集群性能、服务器调优需要投入精力,我们研发需要负责业务SQL执行优化。当业务数据量达到一定规模后,SQL执行效率可能就会出现瓶颈,影响系统业务响应。掌握如何判断SQL执行慢、以及如何分析SQL执行计划、优化SQL的技能,在工作中解决SQL性能问题显得非常关键。
|
8月前
|
SQL
【YashanDB知识库】使用leading hint调整SQL执行计划后报错YAS-04522 invalid hint leading
【YashanDB知识库】使用leading hint调整SQL执行计划后报错YAS-04522 invalid hint leading
【YashanDB知识库】使用leading hint调整SQL执行计划后报错YAS-04522 invalid hint leading
|
9月前
|
SQL
【YashanDB 知识库】使用 leading hint 调整 SQL 执行计划后报错 YAS-04522 invalid hint leading
在 YashanDB 的所有版本中,使用 leading hint 调整 SQL 执行计划时可能出现“YAS-04522 invalid hint leading”错误,导致 SQL 无法正常执行。原因是 YashanDB 优化器的 Bug。解决方法为避免使用 leading hint。可通过创建测试表 a、b、c 并执行特定 SQL 语句来验证问题是否存在。
|
8月前
|
SQL 存储 关系型数据库
【YashanDB知识库】如何从内存中获取SQL语句的执行计划
【YashanDB知识库】如何从内存中获取SQL语句的执行计划
|
8月前
|
SQL
【YashanDB知识库】过期统计信息导致SQL执行计划变差
【YashanDB知识库】过期统计信息导致SQL执行计划变差
|
8月前
|
SQL
【YashanDB知识库】收集分区表统计信息采样率小于1导致SQL执行计划走偏
【YashanDB知识库】收集分区表统计信息采样率小于1导致SQL执行计划走偏
|
SQL Oracle 关系型数据库
Oracle SQL:了解执行计划和性能调优
Oracle SQL:了解执行计划和性能调优
273 1
|
SQL 分布式计算 MaxCompute
SQL开发问题之对于ODPS中的UNION操作,执行计划的问题如何解决
SQL开发问题之对于ODPS中的UNION操作,执行计划的问题如何解决
246 7
|
SQL 运维 安全
数据管理DMS产品使用合集之执行SQL时,如何添加Hint来改变查询的执行计划
阿里云数据管理DMS提供了全面的数据管理、数据库运维、数据安全、数据迁移与同步等功能,助力企业高效、安全地进行数据库管理和运维工作。以下是DMS产品使用合集的详细介绍。
152 1
|
SQL 分布式计算 MaxCompute
ODPS SQL问题之为什么使用odps.sql.groupby.skewindata = true优化后,逻辑执行计划会发生改变如何解决
ODPS SQL问题之为什么使用odps.sql.groupby.skewindata = true优化后,逻辑执行计划会发生改变如何解决
326 0
下一篇
开通oss服务