MySQL执行计划里面的key_len

 
以前看MySQL的执行计划,感觉内容有些简陋,平时分析主要就是看是否全表扫描,索引使用是否合理等。基本上也能分析出很多问题来,但是显然有时候会有些疑惑,那就是对于复合索引,多列值的情况下,到底启用了那些索引列,这个时候索引的使用情况就很值得琢磨琢磨了,我们得根据执行计划里面的key_len做一个重要的参考。

   我们做一个简单的测试来说明。

   CREATE TABLE `department` (
`DepartmentID` int(11) DEFAULT NULL,
`DepartmentName` varchar(20) DEFAULT NULL,
KEY `IND_D` (`DepartmentID`),
KEY `IND_DN` (`DepartmentName`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

运行语句为:explain select count(*)from department\G

对于这个语句,key_len到底是多少呢?

mysql> explain select count(*)from department\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: department
         type: index
possible_keys: NULL
          key: IND_D
      key_len: 5
          ref: NULL
         rows: 1
        Extra: Using index
1 row in set (0.00 sec)
在这个例子里面,possible_keys,key,Extra你看了可能有些晕,我们看看key_len的值为5,这个值是怎么算出来的呢,首先表有两个字段,第一个字段的类型为数值,int的长度为4,因为字段可为null,所以需要一个字节来存储,这样下来就是4+1=5了。由此我们可以看到这个语句是启用了索引ind_d.

  那我们举一反三,把语句修改一下,看看key_len的变化。

mysql>  explain select departmentName from department b where departmentName='TEST'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: b
         type: ref
possible_keys: IND_DN
          key: IND_DN
      key_len: 43
          ref: const
         rows: 1
        Extra: Using where; Using index
1 row in set (0.09 sec)
从上面可以看到,key_len为43,这个值是怎么算出来的呢,我们来掰扯一下,字段2为字符型,长度20,因为是GBK字符集,所以需要乘以2,因为允许字段为NULL,则需要一个字节,对于变长的类型(在此就是VARCHAR),key_len还要加2字节。这样下来就是20*2+1+2=43

   到了这里仅仅是个开始,我们需要看看略微复杂的情况,就需要复合索引了。我们就换一个表test_keylen2

create table test_keylen2 (c1 int not null,c2 int not null,c3 int not null);
alter table test_keylen2 add key  idx1(c1, c2, c3);
下面的语句就很实际了,

explain     SELECT *from test_keylen2 WHERE c1=1 AND c2=1 ORDER BY c1\G    

这个语句中,keylen到底是应该为4或者8还是12呢? 我们就需要验证一下了。

mysql> explain     SELECT *from test_keylen2 WHERE c1=1 AND c2=1 ORDER BY c1\G     
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_keylen2
         type: ref
possible_keys: idx1
          key: idx1
      key_len: 8
          ref: const,const
         rows: 1
        Extra: Using index
1 row in set (0.07 sec)
显然key_len只计算了where中涉及的列,因为是数值类型,所以就是4+4=8

那下面的这个语句呢。

explain   SELECT *from test_keylen2 WHERE c1>=1 and c2=2 \G 

我们添加一个范围,看看这个该如何拆分。

mysql> explain   SELECT *from test_keylen2 WHERE c1>=1 and c2=2 \G  
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_keylen2
         type: index
possible_keys: idx1
          key: idx1
      key_len: 12
          ref: NULL
         rows: 1
        Extra: Using where; Using index
1 row in set (0.07 sec)
在这里就不只是计算where中的列了,而是因为>1的条件直接选择了3个列来计算。

  对于date类型的处理,有一个很细小的差别。我们再换一个表,含有事件类型的字段,

CREATE TABLE `tmp_users` (
`id` int(11) NOT NULL
AUTO_INCREMENT,
`uid` int(11) NOT NULL,
`l_date` datetime NOT NULL,
`data` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ind_uidldate` (`uid`,`l_date`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

下面的语句key_len该如何计算呢。

explain select * from tmp_users where uid = 9527 and l_date >= '2012-12-10 10:13:17'\G

这一点出乎我的意料,按照datetime的印象是8个字节,所以应该是8+4=12,但是这里却偏偏是9,这个数字怎么计算的。
           id: 1
  select_type: SIMPLE
        table: tmp_users
         type: range
possible_keys: ind_uidldate
          key: ind_uidldate
      key_len: 9
          ref: NULL
         rows: 1
        Extra: Using index condition
1 row in set (0.07 sec)
这里就涉及到一个技术细节,是在MySQL 5.6中的datetime的存储差别。在5.6.4以前是8个字节,之后是5个字节

所以按照这个算法就是4+5=9

时间: 2024-09-13 03:17:27

MySQL执行计划里面的key_len的相关文章

MySQL执行计划explain的key_len解析

当用Explain查看SQL的执行计划时,里面有列显示了 key_len 的值,根据这个值可以判断索引的长度,在组合索引里面可以更清楚的了解到了哪部分字段使用到了索引.下面演示中,表结构的合理性这边暂且不说,只是证明一下索引长度的计算方法.目前大部分博文是字符类型的索引长度计算方法,下面列举几个类型的索引长度计算方法: 1.整数类型 (dg1)root@127.0.0.1 [mytest]> desc table_key; +---------+-------------+------+----

mysql执行计划介绍_Mysql

烂sql不仅直接影响sql的响应时间,更影响db的性能,导致其它正常的sql响应时间变长.如何写好sql,学会看执行计划至关重要.下面我简单讲讲mysql的执行计划,只列出了一些常见的情况,希望对大家有所帮助. 测试表结构: 复制代码 代码如下: CREATE TABLE `t1` (  `c1` int(11) NOT NULL DEFAULT '0',  `c2` varchar(128) DEFAULT NULL,  `c3` varchar(64) DEFAULT NULL,  `c4`

MySQL执行计划extra中的using index 和 using where using index 的区别

原文:MySQL执行计划extra中的using index 和 using where using index 的区别   本文出处:http://www.cnblogs.com/wy123/p/7366486.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错误进行修正或补充,无他)   mysql执行计划中的extra列中表明了执行计划的每一步中的实现细节,其中包含了与索引相关的一些细节信息其中跟索引有关的using index

FAQ系列 | 解读EXPLAIN执行计划中的key_len

导读 EXPLAIN中的key_len一列表示什么意思,该如何解读? EXPLAIN执行计划中有一列 key_len 用于表示本次查询中,所选择的索引长度有多少字节,通常我们可借此判断联合索引有多少列被选择了. 在这里 key_len 大小的计算规则是: 一般地,key_len 等于索引列类型字节长度,例如int类型为4-bytes,bigint为8-bytes: 如果是字符串类型,还需要同时考虑字符集因素,例如:CHAR(30) UTF8则key_len至少是90-bytes: 若该列类型定义

mysql 执行计划优化

一条简单的SQL 语句竟花了15.87 sec, 写道 mysql> SELECT x.loc AS loc, x.lastmod AS lastmod, x.changefreq AS changefreq, x.changecount AS changecount, x.priority AS priority, x.language AS language, x.ac cess AS access, x.status AS status FROM xmlsitemap x WHERE (x

ASP.net的UpdatePanel刷新时如何执行HEAD里面的JS代码

问题描述 各位:我的页面中有若干个UpdatePanel,每个UpdatePanel放一个按钮,点击该UpdatePanel中的按钮则向该UpdatePanel插入一个Chart,Chart是用Jqurey的Highcharts生成的.但Jqurey代码只会在页面第一次加载时运行,更新UpdatePanel无法再次运行,因此无法插入图表.网上搜了一下方法,说"局部刷新之后要重新注册js".我用了如下方法:<scripttype="text/javascript"

关于执行计划里recursive calls,db block gets和consistent gets参数的解释

执行 我们在实际工作中经常要看某个sql语句的执行计划,例如: 在sqlplus使用命令SET AUTOTRACE ON后,执行计划显示如下: SELECT STATEMENT Optimizer=ALL_ROWS (Cost=985 Card=1 Bytes=26) Statistics----------------------------------------------------------35 recursive calls0 db block gets1052 consisten

MySQL 索引管理与执行计划

1.1 索引的介绍 索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息.如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息. 索引的一个主要目的就是加快检索表中数据的方法,亦即能协助信息搜索者尽快的找到符合限制条件的记录ID的辅助数据结构. 1.1.1 唯一索引 唯一索引是不允许其中任何两行具有相同索引值的索引.当现有数据中存在重复的键值时,大多数数据库不允许将新创建的唯一索引与表一起保存.数据库还可能防止添加将在表中创

MySQL学习系列2--MySQL执行计划分析EXPLAIN

原文:MySQL学习系列2--MySQL执行计划分析EXPLAIN 1.Explain语法 EXPLAIN SELECT -- 变体:   EXPLAIN EXTENDED SELECT -- 将执行计划"反编译"成SELECT语句,运行SHOW WARNINGS 可得到被MySQL优化器优化后的查询语句   2.执行计划分析和实例 创建员工表Employee create table Employee ( ID int auto_increment, Ename varchar(32