MySQL key_len 大小的计算
背景:
当用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 大小的计算的更多相关文章
- MySQL explain key_len 大小的计算
总结: 变长字段需要额外的2个字节,固定长度字段不需要额外的字节.而null都需要1个字节的额外空间,所以以前有个说法:索引字段最好不要为NULL,因为NULL让统计更加复杂,并且需要额外一个字节的存 ...
- 什么是blob,mysql blob大小配置介绍
什么是blob,mysql blob大小配置介绍 作者: 字体:[增加 减小] 类型:转载 BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器.在计 ...
- C++类对象大小的计算
(一)常规类大小计算 C++类对象计算需要考虑很多东西,如成员变量大小,内存对齐,是否有虚函数,是否有虚继承等.接下来,我将对此举例说明. 以下内存测试环境为Win7+VS2012,操作系统为32位 ...
- 速查mysql数据大小
速查mysql数据大小 # 1.查看所有数据库大小 mysql> select concat(round(sum(DATA_LENGTH/1024/1024),2),'MB') as data ...
- 【MySQL】无法启动mysql服务(位于本地计算机上)错误1067,进程意外中止
好久没看MySQL了,今天启动起来找找感觉,尴尬了...发现服务启动不了.系统提示:无法启动mysql服务(位于本地计算机上)错误1067,进程意外中止. 解决过程: 1.在网上百度好久,看到一条解决 ...
- SQL命令查看Mysql数据库大小
SQL命令查看Mysql数据库大小的方法. 要想知道每个数据库的大小的话,步骤如下:1.进入information_schema 数据库(存放了其他的数据库的信息)use information_sc ...
- 查看MySQL数据库大小
查看MySQL数据库大小 1.首先进入information_schema 数据库(存放了其他的数据库的信息) ? 1 2 mysql> use information_schema; Data ...
- struct和class内存大小的计算
以下均是在VS2017下的结果 结构体内存大小的计算: 用例一: #include<stdio.h> union ss { int a; char b; }; struct MyStruc ...
- CNN中感受野大小的计算
1 感受野的概念 从直观上讲,感受野就是视觉感受区域的大小.在卷积神经网络中,感受野的定义是 卷积神经网络每一层输出的特征图(feature map)上的像素点在原始图像上映射的区域大小. 2 感受野 ...
随机推荐
- 使用supervisor监控进程
在linux下监控进程,可以使用inittab,最近找到了supervisor,也很好用,记录一下:1.系统要安装python,并安装与之对应的setuptools,下载地址在此2.安装:# sh s ...
- MYSql存储过程的作用及语法
1.使用了存过程,很多相似性的删除,更新,新增等操作就变得轻松了,并且以后也便于管理! 2.存储过程因为SQL语句已经预编绎过了,因此运行的速度比较快. 3.存储过程可以接受参数.输出参数.返回单个或 ...
- linux下定时执行任务方法【转】
之前就转过一篇关于定时任务的文章,前俩天用,还的翻出来看!!!再转一次,备用,,需要的时候不用麻烦找! ----------------------------------------------- ...
- UvaLive6662 The Last Ant 模拟
UvaLive6662 PDF题目 题意:给出隧道长度L,蚂蚁数量N,各蚂蚁位置Pi.前进方向Di,都为整数(前进方向为L或R),蚂蚁速度为1cm每秒,两蚂蚁若在整数点相遇则都反向,若不在整数点相遇则 ...
- sql字段中逗号分隔字符串的判断
例如,数据表t1中有一个字段PlayTheme存放的数值类似如下: 第一行:1,2,12 第二行:22,222,2222 第三行:1,2 第四行:2,12 第五行:2 如果你想取出PlayTheme字 ...
- github及其他记录
http://mvnrepository.com/artifact/org.jdom/jdom/1.1.3 https://github.com/open-power-workgroup/Hospit ...
- 解析某些特殊格式XML文件时,获取不到根节点问题
还是在语音识别这块.在读取本地的SRGS的XML后,无法获取到根节点<grammar>. 下面是SRGS.XML文件(只给出了根节点) <?xml version="1.0 ...
- POJ 1925 Spiderman
Spiderman Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 5858 Accepted: 1143 Description ...
- 【bzoj2060】[Usaco2010 Nov]Visiting Cows拜访奶牛
题目描述 经过了几周的辛苦工作,贝茜终于迎来了一个假期.作为奶牛群中最会社交的牛,她希望去拜访N(1<=N<=50000)个朋友.这些朋友被标号为1..N.这些奶牛有一个不同寻常的交通系统 ...
- MySql的count统计结果
起因:最近在学习mysql的数据库,发现在innodb表中大数据量下count(*)的统计结果实在是太慢,所以想找个办法替代这种查询,下面分享一下我查找的过程. 实践:在给出具体的结论之前,我们先看看 ...