背景:

当用Explain查看SQL的执行计划时,里面有列显示了 key_len 的值,根据这个值可以判断索引的长度,在组合索引里面可以更清楚的了解到了哪部分字段使用到了索引。

环境:

CREATE TABLE `tmp_0612` (
`id` int(11) NOT NULL,
`name` varchar(10) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`address` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

插入数据:

insert into tmp_0612 values(1,'a',11,'hz'),(2,'b',22,'gz'),(3,'c',33,'aa');

创建索引:

alter table tmp_0612 add index idx_name(name);
alter table tmp_0612 add index idx_age(age);

测试:

explain select * from tmp_0612 where name ='a';
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tmp_0612 | ref | idx_name | idx_name | 33 | const | 1 | Using index condition |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+

从上面的执行计划可知,索引的长度是33。比预想的30(10*3(utf8))要高出3字节,为什么呢?进一步测试:

修改name 成 not null

alter table tmp_0612 modify name varchar(10) not null;

再看执行计划:

explain select * from tmp_0612 where name ='a';
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tmp_0612 | ref | idx_name | idx_name | 32 | const | 1 | Using index condition |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+

发现上面的执行计划和第一次的有区别(key_len),经过多次测试,发现字段允许NULL的会多出一个字节。想到了之前的一篇文章,NULL是需要一个标志位的,占用1个字符。那还有2个字节怎么算?这里想到的是会不会和 多字节字符集 相关?那改字符集试试:

alter table tmp_0612 convert to charset latin1;

explain select * from tmp_0612 where name ='a';
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tmp_0612 | ref | idx_name | idx_name | 12 | const | 1 | Using index condition |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+

发现还是多了2个字节,看来和多字节字符集没有关系了。那会不会和 变长字段 有关系?再试试:

alter table tmp_0612 convert to charset utf8;

alter table tmp_0612 modify name char(10) not null;

explain select * from tmp_0612 where name ='a';
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tmp_0612 | ref | idx_name | idx_name | 30 | const | 1 | Using index condition |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+

和预料的一样了,是30=10*3。到这里相信大家都已经很清楚了,要是还比较模糊就看反推到33字节。

改成允许NULL,应该会变成31。

alter table tmp_0612 modify name char(10);

explain select * from tmp_0612 where name ='a';
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tmp_0612 | ref | idx_name | idx_name | 31 | const | 1 | Using index condition |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+

改成变长字段类型,应该会变成33。

alter table tmp_0612 modify name varchar(10);

explain select * from tmp_0612 where name ='a';
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tmp_0612 | ref | idx_name | idx_name | 33 | const | 1 | Using index condition |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+

改成单字节字符集,还是还是需要额外的3字节(1:null ;变长字段:2),和字符集无关。

alter table tmp_0612 convert to charset latin1;

explain select * from tmp_0612 where name ='a';
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tmp_0612 | ref | idx_name | idx_name | 13 | const | 1 | Using index condition |
+----+-------------+----------+------+---------------+----------+---------+-------+------+-----------------------+

反推上去都和预测的一样。

其他测试:

explain select * from tmp_0612 where age = 11;
+----+-------------+----------+------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | tmp_0612 | ref | idx_age | idx_age | 5 | const | 1 | NULL |
+----+-------------+----------+------+---------------+---------+---------+-------+------+-------+ alter table tmp_0612 modify age int not null; explain select * from tmp_0612 where age = 11;
+----+-------------+----------+------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | tmp_0612 | ref | idx_age | idx_age | 4 | const | 1 | NULL |
+----+-------------+----------+------+---------------+---------+---------+-------+------+-------+

int 是占4个字符的,上面key_len的也是符合预期。关于组合索引的,可以自己去测试玩。

总结:

变长字段需要额外的2个字节,固定长度字段不需要额外的字节。而null都需要1个字节的额外空间,所以以前有个说法:索引字段最好不要为NULL,因为NULL让统计更加复杂,并且需要额外一个字节的存储空间。

key_len的长度计算公式:

varchr(10)变长字段且允许NULL      : 10*(Character Set:utf8=3,gbk=2,latin1=1)+1(NULL)+2(变长字段)
varchr(10)变长字段且不允许NULL : 10*(Character Set:utf8=3,gbk=2,latin1=1)+2(变长字段) char(10)固定字段且允许NULL : 10*(Character Set:utf8=3,gbk=2,latin1=1)+1(NULL)
char(10)固定字段且不允许NULL : 10*(Character Set:utf8=3,gbk=2,latin1=1)

MySQL key_len 大小的计算的更多相关文章

  1. MySQL explain key_len 大小的计算

    总结: 变长字段需要额外的2个字节,固定长度字段不需要额外的字节.而null都需要1个字节的额外空间,所以以前有个说法:索引字段最好不要为NULL,因为NULL让统计更加复杂,并且需要额外一个字节的存 ...

  2. 什么是blob,mysql blob大小配置介绍

    什么是blob,mysql blob大小配置介绍 作者: 字体:[增加 减小] 类型:转载   BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器.在计 ...

  3. C++类对象大小的计算

    (一)常规类大小计算 C++类对象计算需要考虑很多东西,如成员变量大小,内存对齐,是否有虚函数,是否有虚继承等.接下来,我将对此举例说明. 以下内存测试环境为Win7+VS2012,操作系统为32位 ...

  4. 速查mysql数据大小

    速查mysql数据大小 # 1.查看所有数据库大小 mysql> select concat(round(sum(DATA_LENGTH/1024/1024),2),'MB') as data ...

  5. 【MySQL】无法启动mysql服务(位于本地计算机上)错误1067,进程意外中止

    好久没看MySQL了,今天启动起来找找感觉,尴尬了...发现服务启动不了.系统提示:无法启动mysql服务(位于本地计算机上)错误1067,进程意外中止. 解决过程: 1.在网上百度好久,看到一条解决 ...

  6. SQL命令查看Mysql数据库大小

    SQL命令查看Mysql数据库大小的方法. 要想知道每个数据库的大小的话,步骤如下:1.进入information_schema 数据库(存放了其他的数据库的信息)use information_sc ...

  7. 查看MySQL数据库大小

    查看MySQL数据库大小 1.首先进入information_schema 数据库(存放了其他的数据库的信息) ? 1 2 mysql> use information_schema; Data ...

  8. struct和class内存大小的计算

    以下均是在VS2017下的结果 结构体内存大小的计算: 用例一: #include<stdio.h> union ss { int a; char b; }; struct MyStruc ...

  9. CNN中感受野大小的计算

    1 感受野的概念 从直观上讲,感受野就是视觉感受区域的大小.在卷积神经网络中,感受野的定义是 卷积神经网络每一层输出的特征图(feature map)上的像素点在原始图像上映射的区域大小. 2 感受野 ...

随机推荐

  1. 您的应用静态链接到的 OpenSSL 版本有多个安全漏洞。建议您尽快更新 OpenSSL

    安全提醒 您的应用静态链接到的 OpenSSL 版本有多个安全漏洞.建议您尽快更新 OpenSSL. 在开头为 1.0.1h.1.0.0m和 0.9.8za的 OpenSSL 版本中这些漏洞已得到修复 ...

  2. linux下google chrome浏览器字体修改

    今天安装了最新的chrome,我是下载的.deb包直接安装的. 安装完后,用chrome浏览页面时,发现字体有的大,有的小,还不清楚. 于是在网上搜索了一下如何设置字体. 1.打开Chrome浏览器. ...

  3. Linux 下 netbeans 字体抗锯齿正解

    转自:http://leenjewel.blog.163.com/blog/static/601937922010124444051/ 说来这个不难,主要是我看网上有的写的不是很明确,甚至有的写的根本 ...

  4. logrotate关于日志轮询和分割

    如果你的是源码包安装的服务,那么对于Linux服务器上的一些服务在运行当中产生的日志很重要,可以判断你的服务是否有异常等,但源码包安装的日志是没有日志的轮询或者说是切割能力的, 所以你就需要用到bas ...

  5. [译]Mongoose指南 - Model

    编译你的第一个model var xxSchema = new Schema({name: 'string', size: 'string'}); var Tank = mongoose.model( ...

  6. Git基本常用命令

    Git基本常用命令如下: mkdir: XX (创建一个空目录 XX指目录名) pwd: 显示当前目录的路径. git init 把当前的目录变成可以管理的git仓库,生成隐藏.git文件. git ...

  7. RGB颜色矩提取算法——Matlab

    一.颜色矩公式 一阶颜色矩——均值,反映图像明暗程度 二阶颜色矩 ——标准差,反映图像颜色分布范围 三阶颜色矩 ——方差,反映图像颜色分布对称性 二.方法一: firstMoment = mean(m ...

  8. Windows Phone自带的语音识别

    WindowsPhone下语音操作包括: 1.程序内部的语音识别,用户可以通过语音识别进行输入或完成相关任务 2.控制程序的语音命令,控制程序启动.打开,并可对页面跳转等进行操作 这篇文章将构建一个简 ...

  9. 【转】AspNetPager分页控件用法

    AspNetPager分页控件解决了分页中的很多问题,直接采用该控件进行分页处理,会将繁琐的分页工作变得简单化,下面是我如何使用AspNetPager控件进行分页处理的详细代码: 1.首先到www.w ...

  10. SpringDataJPA的几个使用记录

    public Page<XMGLFileTemplateDTO> findXMGLFileTemplateByConditions(XMGLFileTemplateDTO xmglFile ...