本文首先介绍了MySQL的查询计划中ken_len的含义;然后介绍了key_len的计算方法;最后通过一个伪造的例子,来说明如何通过key_len来查看联合索引有多少列被使用。

key_len的含义

在MySQL中,可以通过explain查看SQL语句所走的路径,如下所示:

  1. mysql> create table t(a int primary key, b int not null, c int not null, index(b));
     Query OK, 0 rows affected (0.01 sec)
     mysql> explain select b from t ;
     +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
     | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
     +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
     |  1 | SIMPLE      | t     | index | NULL          | b    | 4       | NULL |    1 | Using index |
     +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
     1 row in set (0.00 sec)
其中,key_len表示使用的索引长度,是以字节为单位。在上面的例子中,由于int型占用4个字节,而索引中只包含了1列,所以,key_len是4。

下面是联合索引的情况:

  1. mysql> alter table t add index ix(b, c);
    Query OK, 0 rows affected (0.03 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    mysql> explain select b, c from t ;
    +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
    +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
    |  1 | SIMPLE      | t     | index | NULL          | ix   | 8       | NULL |    1 | Using index |
    +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
    1 row in set (0.00 sec)

联合索引ix包含了2列,并且都使用到了,所以,这里ken_len是8。

到这里,我们已经可以理解key_len的含义了,似乎已经没有什么可讲的了,但是,MySQL中key_len的计算还有很多需要注意的地方。

例如,我们将b这一列的NOT NULL约束去掉,然后ken_len就和我们预期不一样了,如下所示:

  1. mysql> alter table t modify b int;
    Query OK, 0 rows affected (0.01 sec)
    Records: 0  Duplicates: 0  Warnings: 0
     
    mysql> explain select b from t;
    +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
    +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
    |  1 | SIMPLE      | t     | index | NULL          | b    | 5       | NULL |    1 | Using index |
    +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
    1 row in set (0.00 sec)

 

MySQL中key_len计算规则

MySQL中,key_len的计算规则如下:

  1. 如果列可以为空,则在数据类型占用字节的基础上加1,如int型,不能为空key_len为4,可以为空key_len为5
  2. 如果列是变长的,则在数据列所占字节的基数上再加2,如varbinary(10),不能为空,则key_len为10  + 2 ,可以为空则key_len为10+2+1
  3. 如果是字符型,则还需要考虑字符集,如某列的定义是varchar(10),且是utf8,不能为空,则key_len为10 * 3 + 2,可以为空则key_len为10*3+2+1

此外,decimal列的计算方法与上面一样,如果可以为空,则在数据类型占用字节的基础上加1,但是,decimal本身所占用字节数,计算就比较复杂。

根据官方文档可以知道,decimal定义为decimal(M,D),其中,M是总的位数,D是小数点后保留的位数。小数点前与小数点后的数字分开存储,且以9位数为1组,用4个字节保存,如果低于9位数,需要的字节数如下:

  1. Leftover Digits Number of Bytes
  2. -----------------------------
  3. |0 |0 |
  4. |1-2 |1 |
  5. |3-4 |2 |
  6. |5-6 |3 |
  7. |7-9 |4 |
  8. -----------------------------
 

例如:

  • decimal(20,6)=> 小数点左边14位,小数点右边6位 => 小数点左边分组为5 + 9,需要3个字节+4个字节存储,小数点一个分组,需要3个字节存储 => 总共需要10个字节
  • decimal(18,9)=> 小数点左边9位数,小数点右边9位数 => 分别使用4个字节存储 => 共需要 8个字节
  • decimal(18,2)=> 小数点左边16位数,小数点右边2位数 => 分组为7 + 9,需要8个字节存储,小数点右边1个字节存储 => 共需要9个字节

通过key_len分析联合索引

如下所示,我们定义了一个表t,表t包含a、b、c、d共4列:

  1. mysql> show create table t\G
    *************************** 1. row ***************************
           Table: t
    Create Table: CREATE TABLE `t` (
      `a` int(11) NOT NULL,
      `b` int(11) DEFAULT NULL,
      `c` int(11) DEFAULT NULL,
      `d` int(11) DEFAULT NULL,
      PRIMARY KEY (`a`),
      KEY `ix_x` (`b`,`d`,`c`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)

 

现在要执行SQL语句如下:
select a from t where b = 5 and d = 10 order by c;

 

假设我们有一个索引ix_x(b,d,c),通过explain得到如下输出:

  1. mysql> explain select a from t where b = 5 and d = 10 order by c;
    +----+-------------+-------+------+---------------+------+---------+-------------+------+--------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref         | rows | Extra                    |
    +----+-------------+-------+------+---------------+------+---------+-------------+------+--------------------------+
    |  1 | SIMPLE      | t     | ref  | ix_x          | ix_x | 10      | const,const |    1 | Using where; Using index |
    +----+-------------+-------+------+---------------+------+---------+-------------+------+--------------------------+
    1 row in set (0.00 sec)

 

可以看到,查询语句使用了联合索引中的b和d两列来过滤数据。

如果我们定义的联合索引不是`ix_x(b,d,c)`,而是`ix_x(b, c, d)`,通过explain得到的输入如下:

  1. mysql> alter table t drop index ix_x;
    mysql> alter table t add index ix_x(b, c, d);
    mysql> explain select a from t where b = 5 and d = 10 order by c;
    +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra                    |
    +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
    |  1 | SIMPLE      | t     | ref  | ix_x          | ix_x | 5       | const |    2 | Using where; Using index |
    +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
    1 row in set (0.00 sec)

key_len为5,也就是说,只用到了联合索引中的第一列,可以看到,虽然联合索引包含了我们要查询的所有列,但是,由于定义的顺序问题,SQL语句并不能够充分利用索引。
 
 

MySQL的查询计划中ken_len的值计算的更多相关文章

  1. Mysql子查询IN中使用LIMIT

    学习下Mysql子查询IN中使用LIMIT的方法. 这两天项目里出了一个问题,mysql LIMIT使用后报错. 需求是这样的,我有3张表,infor信息表,mconfig物料配置表,maaply物料 ...

  2. linq 在查询表达式中处理 null 值

    此示例显示如何在源集合中处理可能的 null 值. IEnumerable<T> 等对象集合可包含值为 null 的元素. 如果源集合为 null 或包含值为 null 的元素,并且查询不 ...

  3. mysql在查询结果中增加排序字段

    ELECT userId , () AS runRank , mostFast1 FROM user_info, ()) b WHERE mostFast1 IS NOT NULL ORDER BY ...

  4. mysql 在查询结果中进行二次查询

    第一次查询:查询身份证编号和出现次数 select cardid,count(cardid) as total from p_person_info group by cardid 在第一次查询结果进 ...

  5. 【MySql】查询数据库中所有表及列的信息

    SELECT TABLE_NAME, -- 表名 COLUMN_NAME, -- 字段名 DATA_TYPE, -- 字段类型 COLUMN_COMMENT -- 字段注释 FROM INFORMAT ...

  6. nodejs怎么同步从一个数据库查询函数中返回一个值

    var sql=require('msnodesql'); var conn_str="Driver={SQL Server Native Client 11.0};Server={127. ...

  7. mysql数据库查询库中所有表所占空间大小

    SELECT CONCAT(table_schema,'.',table_name) AS 'TABLE_NAME', CONCAT(, ),'M') AS 'ROW_SIZE', CONCAT( ) ...

  8. MySQL查询计划 key_len计算方法

    本文首先介绍了MySQL的查询计划中ken_len的含义:然后介绍了key_len的计算方法:最后通过一个伪造的例子,来说明如何通过key_len来查看联合索引有多少列被使用. key_len的含义 ...

  9. MYSQL查询计划KEY_LEN

    http://www.innomysql.com/article/25241.html 1 key_len的含义 2 MySQL中key_len计算规则 3 通过key_len分析联合索引 本文首先介 ...

随机推荐

  1. js ajax php分页组件

    github  https://github.com/lihefen/pageList html页面 <!DOCTYPE html><html><head>< ...

  2. 基本数据结构(2)——算法导论(12)

    1. 引言     这一篇博文主要介绍链表(linked list),指针和对象的实现,以及有根树的表示. 2. 链表(linked list) (1) 链表介绍      我们在上一篇中提过,栈与队 ...

  3. OpenCASCADE Data Exchange - 3D PDF

    OpenCASCADE Data Exchange - 3D PDF eryar@163.com Abstract. Today most 3D engineering model data are ...

  4. 图标字体 VS 雪碧图——图标字体应用实践

    本文介绍使用图标字体和SVG取代雪碧图的方法.雪碧图是很多网站经常用到的一种技术,但是它有缺点:高清屏会模糊.无法动态变化如hover时候反色.而使用图标字体可以完美解决上述问题,同时具备兼容性好,生 ...

  5. Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  6. Basic Tutorials of Redis(9) -First Edition RedisHelper

    After learning the basic opreation of Redis,we should take some time to summarize the usage. And I w ...

  7. C#开发微信门户及应用(2)--微信消息的处理和应答

    微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下.学习下微信的相关开发,也就成为计划的安排事情之一了.本系列文章希望从一个循序渐进的角度上,全面介绍微 ...

  8. 数据库表结构设计方法及原则(li)

    数据库设计的三大范式:为了建立冗余较小.结构合理的数据库,设计数据库时必须遵循一定的规则.在关系型数据库中这种规则就称为范式.范式是符合某一种设计要求的总结.要想设计一个结构合理的关系型数据库,必须满 ...

  9. Nginx配置文件nginx.conf中文详解(转)

    ######Nginx配置文件nginx.conf中文详解##### #定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于CPU总核心数. worker_ ...

  10. 解决ngnix服务器上的Discuz!x2.5 Upload Error:413错误

    1.修改php.ini sudo nano /etc/php5/fpm/php.ini #打开php.ini找到并修改以下的参数,目的是修改上传限制 max_execution_time = 900 ...