导读
执行计划中看到key_len值发生变化,表示联合索引有时能用到多个列,有时却只能用到部分列,这是为啥子呢?
我的朋友小明同学这几天又遇到一件令人懵*的事,有个SQL执行计划看起来挺诡异的,我看了下,也是有点发懵。
基本信息
严格遵循我自己要求的“提问的艺术”,先交代下必要的背景信息。
1、表DDL(建议手机横过来观看)
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>