MySQL 执行计划中的 key_len 表示什么
895 total views, 1 views today
我们在使用MySQL中的 explain 命令查看执行计划中,往往能看到key_len
这个指标。
使用复合索引时,通过key_len
的值能判定SQL使用了索引中的哪些字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
root@ 14:37: [sbtest1]> show create table sbtest1\G *************************** 1. row *************************** Table: sbtest1 Create Table: CREATE TABLE `sbtest1` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `k` int(10) unsigned NOT NULL DEFAULT '0', `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '', `in_time` date DEFAULT NULL, PRIMARY KEY (`id`), KEY `k_1` (`k`), KEY `idx_k_pad` (`k`,`pad`) ) ENGINE=InnoDB AUTO_INCREMENT=500001 DEFAULT CHARSET=utf8mb4 MAX_ROWS=1000000 1 row in set (0.00 sec) root@ 14:38: [sbtest1]> explain select * from sbtest1 where k='3' and pad='2342'; +----+-------------+---------+------------+------+---------------+-----------+---------+-------------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+------+---------------+-----------+---------+-------------+------+----------+-------+ | 1 | SIMPLE | sbtest1 | NULL | ref | idx_k_pad | idx_k_pad | 244 | const,const | 1 | 100.00 | NULL | +----+-------------+---------+------------+------+---------------+-----------+---------+-------------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec) `k` int(10) 4*10=40 `pad` char(60) 60*3=180 |
长度计算方法
1.字符集
字符集不同,字符占据的字节长度也不同。
字符集 | 字节长度 |
---|---|
gbk | 1个字符占2个字节 |
utf8 | 1个字符占3个字节 |
utf8mb4 | 1个字符占4个字节 |
2.数据类型占字节长度
数据类型 | 字节长度 |
---|---|
int(n) | 4 |
tinyint(n) | 1 |
timestamp | 4 |
date | 4 |
datetime | 8 |
varchar(n) | n*4+2 |
char(n) | n*4 |
int、tinyint等字段无论定义长度是多少,其占用字节长度是不变的。
3.附加信息
-
定长类型: char、int、datetime、timestamp等,如果
列定义为空
,那么需要占用一个1字节;如果非空,则不占用字节。
-
变长类型:varchar等类型,是否为空的标记占用2个字节。
案例分析
案例1
开头的例子中,key_len
的值为244。
1 2 3 4 5 6 7 8 |
root@ 14:38: [sbtest1]> explain select * from sbtest1 where k='3' and pad='2342'; +----+-------------+---------+------------+------+---------------+-----------+---------+-------------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+------+---------------+-----------+---------+-------------+------+----------+-------+ | 1 | SIMPLE | sbtest1 | NULL | ref | idx_k_pad | idx_k_pad | 244 | const,const | 1 | 100.00 | NULL | +----+-------------+---------+------------+------+---------------+-----------+---------+-------------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec) |
索引KEY idx_k_pad
(k
,pad
)。k int(10) 、pad char(60) ,且两个字段都为非空,不需要占用多余的字节。
我们来计算key_len长度: 4 + 4*60=244。说明SQL使用到了索引idx_k_pad
的所有字段。
案例2
还是同一张表,SQL使用同样的索引,但是key_len
值则不同。
1 2 3 4 5 6 7 |
root@ 16:04: [sbtest1]> explain select * from sbtest1 where k='3' ; +----+-------------+---------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ | 1 | SIMPLE | sbtest1 | NULL | ref | idx_k_pad | idx_k_pad | 4 | const | 3 | 100.00 | NULL | +----+-------------+---------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec) |
这次只用到了索引中一部分,也就是k列,k int(10),非空占据4字节。
参考
https://segmentfault.com/a/1190000015605006