相似的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
...

好吧,又涨姿势了。

相关文章
|
SQL 缓存 数据库
OBCP第三章 SQL引擎高级技术-执行计划
OBCP第三章 SQL引擎高级技术-执行计划
303 0
|
1月前
|
SQL Oracle 关系型数据库
Oracle SQL:了解执行计划和性能调优
Oracle SQL:了解执行计划和性能调优
45 1
|
4月前
|
SQL 分布式计算 MaxCompute
SQL开发问题之对于ODPS中的UNION操作,执行计划的问题如何解决
SQL开发问题之对于ODPS中的UNION操作,执行计划的问题如何解决
|
5月前
|
SQL 运维 安全
数据管理DMS产品使用合集之执行SQL时,如何添加Hint来改变查询的执行计划
阿里云数据管理DMS提供了全面的数据管理、数据库运维、数据安全、数据迁移与同步等功能,助力企业高效、安全地进行数据库管理和运维工作。以下是DMS产品使用合集的详细介绍。
57 1
|
4月前
|
SQL 分布式计算 MaxCompute
ODPS SQL问题之为什么使用odps.sql.groupby.skewindata = true优化后,逻辑执行计划会发生改变如何解决
ODPS SQL问题之为什么使用odps.sql.groupby.skewindata = true优化后,逻辑执行计划会发生改变如何解决
|
5月前
|
SQL 关系型数据库 MySQL
MySQL数据库——索引(4)-SQL性能分析-profile详情、explain(profile查看指令,explain执行计划中各个字段的含义)
MySQL数据库——索引(4)-SQL性能分析-profile详情、explain(profile查看指令,explain执行计划中各个字段的含义)
62 2
|
SQL 缓存 OLTP
OBCP第三章 SQL引擎技术-执行计划缓存
OBCP第三章 SQL引擎技术-执行计划缓存
136 0
|
SQL 关系型数据库 MySQL
使用explain分析你SQL执行计划
使用explain分析你SQL执行计划
|
SQL 缓存 监控
Oracle中如何生成有用的SQL 执行计划(译)
漫画戴夫·艾伦(Dave Allen)曾经讲过一个古老的笑话,一个旅行者问路人去某个城镇的路,路人只是说:“如果我是你,我就不会从这里开始。”
162 0
|
SQL 存储 缓存
获取和解读Oracle中SQL的执行计划(译文)
生成和显示 SQL 语句的执行计划是大多数 DBA、SQL 开发人员和性能专家的常见任务,因为它提供了 SQL 语句执行性能相关的信息。执行计划显示执行 SQL 语句的详细步骤,这些步骤表示为一组使用和生成行的数据库运算符。运算符的顺序和实现由查询优化器根据查询转换和物理优化技术来决定。
322 0

热门文章

最新文章

下一篇
无影云桌面