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 大小的计算

时间: 2024-10-13 00:43:49

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

查看mysql库大小,表大小,索引大小

说明: 通过MySQL的 information_schema 数据库,可查询数据库中每个表占用的空间.表记录的行数:该库中有一个 TABLES 表,这个表主要字段分别是: TABLE_SCHEMA : 数据库名TABLE_NAME:表名ENGINE:所使用的存储引擎TABLES_ROWS:记录数DATA_LENGTH:数据大小INDEX_LENGTH:索引大小 其他字段请参考MySQL的手册,查看一个表占用空间的大小,那就相当于是 数据大小 + 索引大小 . 查看所有库的大小 mysql> u

sql语句查看mysql数据库大小

1.查看mysql数据库大小SELECT sum(DATA_LENGTH)+sum(INDEX_LENGTH)FROM information_schema.TABLES where TABLE_SCHEMA='数据库名';得到的结果是以字节为单位,除1024为K,除1048576(=1024*1024)为M. 2.查看表的最后mysql修改时间select TABLE_NAME,UPDATE_TIME from INFORMATION_SCHEMA.tables where TABLE_SCH

文件大小的计算和文件夹大小的计算

1读取本地documents文件里文件夹的大小(我们可以利用NSDirectoryEnumerator这个类) NSString * Docupath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; //    一般不要吧文件直接放到documents文件夹下,要创建新的文件夹 NSString * filePath = [Docupath stringByAppendin

【c语言】位段大小的计算以及宏的应用

// 位段大小的计算以及宏的应用 #include <stdio.h> #include <malloc.h> #define MAX_SIZE A+B struct _Record_Struct { unsigned char Env_Alarm_ID : 4; unsigned char Paral : 2; unsigned char state; unsigned char avail : 1; }*Env_Alarm_Record; int main() { int A

查看mysql数据库大小、表大小和最后修改时间

查看数据库表基本信息. select * from information_schema.TABLES where information_schema.TABLES.TABLE_SCHEMA = '数据库名' and information_schema.TABLES.TABLE_NAME = '表名'; 查看mysql数据库大小 SELECT sum(DATA_LENGTH)+sum(INDEX_LENGTH) FROM information_schema.TABLES where TAB

Mysql数据库大小查询

1.进入 information_schema 数据库(存放了其他的数据库的信息) use information_schema; 2.查询所有数据的大小: SELECT concat(round(sum(DATA_LENGTH/1024/1024),2),'MB') as data FROM TABLES; 3.查看指定数据库的大小: 比如查看数据库hellodb的大小 SELECT concat(round(sum(DATA_LENGTH/1024/1024),2),'MB') as dat

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

什么是blob,mysql blob大小配置介绍 作者: 字体:[增加 减小] 类型:转载 BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器.在计算机中,BLOB常常是数据库中用来存储二进制文件的字段类型 BLOB是一个大文件,典型的BLOB是一张图片或一个声音文件,由于它们的尺寸,必须使用特殊的方式来处理(例如:上传.下载或者存放到一个数据库).根据Eric Raymond的说法,处理BLOB的主要思想就是让文件处理器(如数据库管理器)不去理会

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

好久没看MySQL了,今天启动起来找找感觉,尴尬了...发现服务启动不了.系统提示:无法启动mysql服务(位于本地计算机上)错误1067,进程意外中止. 解决过程: 1.在网上百度好久,看到一条解决路线是找到window事件查看器:桌面--计算机--右键进入事件查看器. 图片提示:Bind on TCP/IP port: No such file or directory:绑定的TCP / IP端口:没有这样的文件或目录. 图片提示:Do you already have another my

struct和class内存大小的计算

结构体内存大小的计算: 用例一: #include<stdio.h> union ss { int a; char b; }; struct MyStruct { int temp1;//4个字节 char temp2;//一个字节,补齐3个字节 ss aa;//4个字节 char temp3;//一个字节 char temp4;//一个字节,补齐两个字节 }; int main() { printf("%d", sizeof(MyStruct)); return 0; }