MySQL执行计划explain的key_len解析
前言:当用Explain查看SQL的执行计划时,里面有列显示了 key_len 的值,根据这个值可以判断索引的长度,在组合索引里面可以更清楚的了解到了哪部分字段使用到了索引。下面演示中,表结构的合理性这边暂且不说,只是证明一下索引长度的计算方法。目前大部分博文是字符类型的索引长度计算方法,下面列举几个类型的索引长度计算方法
1、整数类型
(dg1)root@127.0.0.1 [mytest]> desc table_key;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id | int() | NO | | NULL | |
| sid | bigint() | NO | | | |
| name | char() | YES | | NULL | |
| age | tinyint() | YES | | NULL | |
| sex | tinyint() | NO | | NULL | |
| address | varchar() | YES | MUL | NULL | |
+---------+-------------+------+-----+---------+-------+
rows in set (0.01 sec) (dg1)root@127.0.0.1 [mytest]>create index age_index on table_key (age); 来看看tinyint类型的索引长度,在NOT NULL 和 NULL 的时候 分别是1和2,tinyint字段长度为1,因为NULL 需要额外一个字节标记为空
(dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where age=;
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+----------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+----------+-------+
| | SIMPLE | table_key | ref | age_index | age_index | 1 | const | | 100.00 | NULL |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+----------+-------+
row in set, warning (0.00 sec) (dg1)root@127.0.0.1 [mytest]> alter table table_key modify age tinyint(); (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where age=;
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+----------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+----------+-------+
| | SIMPLE | table_key | ref | age_index | age_index | 2 | const | | 100.00 | NULL |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+----------+-------+
row in set, warning (0.00 sec) (dg1)root@127.0.0.1 [mytest]>
看看bigint类型的索引长度,同样是 NOT NULL 和 NULL值的时候,分别是8和9,聪明的你应该知道了,bigint长度为8。
(dg1)root@127.0.0.1 [mytest]> alter table table_key add key sid_index (sid);
Query OK, rows affected (0.04 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> desc select * from table_key where sid=;
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| | SIMPLE | table_key | ref | sid_index | sid_index | | const | | NULL |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
row in set (0.00 sec) (dg1)root@127.0.0.1 [mytest]> (dg1)root@127.0.0.1 [mytest]> alter table table_key modify sid bigint();
Query OK, rows affected (0.08 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> desc select * from table_key where sid=;
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| | SIMPLE | table_key | ref | sid_index | sid_index | | const | | NULL |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
row in set (0.00 sec) 看看smallint类型索引长度,同样是 NOT NULL 和 NULL值的时候,分别是2和3 smallint长度为2,允许为空需要一个字节标记
(dg1)root@127.0.0.1 [mytest]> alter table table_key modify sid smallint not null default ;
Query OK, rows affected (0.04 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> desc select * from table_key where sid=;
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| | SIMPLE | table_key | ref | sid_index | sid_index | | const | | NULL |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
row in set (0.00 sec) (dg1)root@127.0.0.1 [mytest]> alter table table_key modify sid smallint ;
Query OK, rows affected (0.07 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> desc select * from table_key where sid=;
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| | SIMPLE | table_key | ref | sid_index | sid_index | | const | | NULL |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
row in set (0.00 sec) 看看mediumint类型索引长度,同样是 NOT NULL 和 NULL值的时候,分别是3和4 (dg1)root@127.0.0.1 [mytest]> alter table table_key modify sid mediumint NOT NULL;
Query OK, rows affected (0.06 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> desc select * from table_key where sid=;
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| | SIMPLE | table_key | ref | sid_index | sid_index | | const | | NULL |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
row in set (0.00 sec) (dg1)root@127.0.0.1 [mytest]> (dg1)root@127.0.0.1 [mytest]> alter table table_key modify sid mediumint ;
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
(dg1)root@127.0.0.1 [mytest]> desc select * from table_key where sid=6;
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
| 1 | SIMPLE | table_key | ref | sid_index | sid_index | 4 | const | 1 | NULL |
+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------+
1 row in set (0.00 sec)
(dg1)root@127.0.0.1 [mytest]>
整数类型索引长度跟字段长度有关,如果允许为空,需要额外一个字节去标记为空
2.浮点数类型
表结构
CREATE TABLE `table_key1` (
`id` int NOT NULL AUTO_INCREMENT ,
`c1` float NOT NULL ,
`c2` double NOT NULL ,
`c3` decimal NOT NULL ,
`c4` date NOT NULL ,
`c5` timestamp NOT NULL ON UPDATE CURRENT_TIMESTAMP ,
`c6` datetime NOT NULL ,
PRIMARY KEY (`id`)
)
看看float类型的索引长度,NOT NULL和NULL的时候,分别是4和5
(dg1)root@127.0.0.1 [mytest]> desc select * from table_key1 where c1 = '3.22';
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| | SIMPLE | table_key1 | ref | c1_index | c1_index | | const | | Using index condition |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
row in set (0.00 sec) (dg1)root@127.0.0.1 [mytest]> alter table table_key1 modify c1 float;
Query OK, rows affected (0.05 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> desc select * from table_key1 where c1 = '3.22';
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| | SIMPLE | table_key1 | ref | c1_index | c1_index | | const | | Using index condition |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
row in set (0.00 sec)
看看double类型的索引长度,NOT NULL和NULL的时候,分别是8和9
(dg1)root@127.0.0.1 [mytest]> alter table table_key1 add key c2_index (c2);
Query OK, rows affected (0.04 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> desc select * from table_key1 where c2 = '3.22';
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
| | SIMPLE | table_key1 | ref | c2_index | c2_index | | const | | NULL |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
row in set (0.00 sec) (dg1)root@127.0.0.1 [mytest]> alter table table_key1 modify c2 double;
Query OK, rows affected (0.03 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> desc select * from table_key1 where c2 = '3.22';
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
| | SIMPLE | table_key1 | ref | c2_index | c2_index | | const | | NULL |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
row in set (0.00 sec) (dg1)root@127.0.0.1 [mytest]>
3、看看时间类型
看看date类型的索引长度,在NOT NULL和NULL的时候,分别是3和4
(dg1)root@127.0.0.1 [mytest]> desc select * from table_key1 where c4 = '2015-05-06';
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| | SIMPLE | table_key1 | ref | c4_index | c4_index | | const | | Using index condition |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
row in set, warnings (0.00 sec) (dg1)root@127.0.0.1 [mytest]> (dg1)root@127.0.0.1 [mytest]> alter table table_key1 modify c4 date;
Query OK, rows affected (0.09 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> desc select * from table_key1 where c4 = '2015-05-06';
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| | SIMPLE | table_key1 | ref | c4_index | c4_index | | const | | Using index condition |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
row in set, warnings (0.00 sec) (dg1)root@127.0.0.1 [mytest]> 在timestamp类型的时候索引长度,在NOT NULL 和 NULL的时候,分别是4和5 (dg1)root@127.0.0.1 [mytest]> desc select * from table_key1 where c5 = '2015-05-06 11:23:21' ;
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| | SIMPLE | table_key1 | ref | c5_index | c5_index | | const | | Using index condition |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
row in set, warnings (0.00 sec) (dg1)root@127.0.0.1 [mytest]> dg1)root@127.0.0.1 [mytest]> alter table table_key1 modify c5 timestamp ON UPDATE CURRENT_TIMESTAMP ;
Query OK, rows affected (0.06 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> (dg1)root@127.0.0.1 [mytest]> desc select * from table_key1 where c5 = '2015-05-06 110:23:21';
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| | SIMPLE | table_key1 | ref | c5_index | c5_index | | const | | Using index condition |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
row in set, warnings (0.00 sec) (dg1)root@127.0.0.1 [mytest]> ##############################在大家认识里datetime是八个字节的长度,下面就来看看,是不是真的这样
(dg1)root@localhost [mytest]> alter table table_key1 modify c6 datetime not null;
Query OK, rows affected (0.03 sec)
Records: Duplicates: Warnings: (dg1)root@localhost [mytest]> desc select * from table_key1 where c6 = '2015-05-06 11:10:36';
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
| | SIMPLE | table_key1 | ref | c6_index | c6_index | | const | | NULL |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
row in set (0.00 sec) (dg1)root@localhost [mytest]> alter table table_key1 modify c6 datetime null;
Query OK, rows affected (0.06 sec)
Records: Duplicates: Warnings: (dg1)root@localhost [mytest]> desc select * from table_key1 where c6 = '2015-05-06 11:10:36';
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
| | SIMPLE | table_key1 | ref | c6_index | c6_index | | const | | NULL |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
row in set (0.00 sec)
颠覆了我们认识,datetime不是8个字节么,下面来看一下MySQL的版本,没错MySQL5.6是datetime长度是5个字节 (dg1)root@localhost [mytest]> \s
--------------
mysql Ver 14.14 Distrib 5.6., for linux-glibc2. (x86_64) using EditLine wrapper Connection id:
Current database: mytest
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.6.-log MySQL Community Server (GPL)
Protocol version:
Connection: Localhost via UNIX socket
Server characterset: gbk
Db characterset: gbk
Client characterset: gbk
Conn. characterset: gbk
UNIX socket: /opt/app/mysql/mysql3307.socket
Uptime: min sec Threads: Questions: Slow queries: Opens: Flush tables: Open tables: Queries per second avg: 0.066
-------------- (dg1)root@localhost [mytest]> 那么真的是这样么,
(dg1)root@localhost [mytest]>alter table table_key1 change c6 c6 datetime(6) not null ;
(dg1)root@localhost [mytest]>explain select * from table_key1 where c6='2015-05-06 11:13:12.000000';
+----+-------------+------------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | table_key1 | NULL | ref | c6_index | c6_index | 8 | const | 1 | 100.00 | NULL |
+----+-------------+------------+------------+------+---------------+----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
小结:在MySQL5.6版本,是否还得使用timestamp类型应该是仁者见仁智者见智的问题了,datetime不存毫秒时候五个字节,因为官方文档说了,5.6.4以上版本,时间和毫秒分开存储了。timestamp范围比较窄(1970-2037年),不排除后续版本会修改其范围值
4.字符类型
表结构,字符集是UTF8 (dg1)root@127.0.0.1 [mytest]> desc table_key;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id | int() | NO | | NULL | |
| sid | bigint() | NO | | | |
| name | char() | YES | | NULL | |
| age | tinyint() | YES | | NULL | |
| sex | tinyint() | NO | | NULL | |
| address | varchar() | YES | MUL | NULL | |
+---------+-------------+------+-----+---------+-------+
rows in set (0.01 sec) 看看定长字符类型char的索引长度,在NOT NULL 和NULL中分别为10*3和10*+ (dg1)root@127.0.0.1 [mytest]> alter table table_key add index name_index (name);
Query OK, rows affected (0.01 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where name='zhangsan';
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | name_index | name_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.00 sec) (dg1)root@127.0.0.1 [mytest]> (dg1)root@127.0.0.1 [mytest]> alter table table_key modify name char();
Query OK, rows affected (0.05 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where name='zhangsan';
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | name_index | name_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.00 sec) 看看变长长字符类型varchar的索引长度,在NOT NULL 和NULL中分别为10*+2和10*++ (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where address='shanghai';
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | address_index | address_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.01 sec) (dg1)root@127.0.0.1 [mytest]> (dg1)root@127.0.0.1 [mytest]> alter table table_key modify address varchar();
Query OK, rows affected (0.10 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where address='shanghai';
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | address_index | address_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.00 sec) (dg1)root@127.0.0.1 [mytest]>
修改字符集为GBK,再来看看 (dg1)root@127.0.0.1 [mytest]> ALTER TABLE `table_key` DEFAULT CHARACTER SET=gbk COLLATE=gbk_chinese_ci; (dg1)root@127.0.0.1 [mytest]> ALTER database `mytest` DEFAULT CHARACTER SET=gbk COLLATE=gbk_chinese_ci; (dg1)root@127.0.0.1 [mytest]> show global variables like '%char%';
+--------------------------+--------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------+
| character_set_client | gbk |
| character_set_connection | gbk |
| character_set_database | gbk |
| character_set_filesystem | binary |
| character_set_results | gbk |
| character_set_server | gbk |
| character_set_system | utf8 |
| character_sets_dir | /opt/app/mysql/share/charsets/ |
+--------------------------+--------------------------------+
rows in set (0.00 sec) 奇怪了,为什么还是10*++1呢,是因为字段的字符集还没修改过来
(dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where address='shanghai';
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | address_index | address_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.01 sec) (dg1)root@127.0.0.1 [mytest]> ALTER TABLE `table_key` MODIFY COLUMN `name` char() CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL , DEFAULT CHARACTER SET=gbk COLLATE=gbk_chinese_ci;
Query OK, rows affected (0.04 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> ALTER TABLE `table_key` MODIFY COLUMN `address` char() CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL , DEFAULT CHARACTER SET=gbk COLLATE=gbk_chinese_ci;
Query OK, rows affected (0.03 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where address='shanghai';
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | address_index | address_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.00 sec) (dg1)root@127.0.0.1 [mytest]>
(dg1)root@127.0.0.1 [mytest]> alter table table_key modify address varchar();
Query OK, rows affected (0.04 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where address='shanghai';
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | address_index | address_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.01 sec) (dg1)root@127.0.0.1 [mytest]> (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where name='zhangsan';
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | name_index | name_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.00 sec) (dg1)root@127.0.0.1 [mytest]> (dg1)root@127.0.0.1 [mytest]> alter table table_key modify name char();
Query OK, rows affected (0.00 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where name='zhangsan';
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | name_index | name_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.01 sec)
来看看复合索引的key_len,(刚才测试GBK字符集,字符集转换成GBK了)
(dg1)root@127.0.0.1 [mytest]> desc table_key;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| sid | bigint(20) | NO | | 0 | |
| name | char(10) | NO | | | |
| age | tinyint(4) | YES | | NULL | |
| sex | tinyint(4) | NO | | NULL | |
| address | varchar(10) | NO | MUL | | |
+---------+-------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
(dg1)root@127.0.0.1 [mytest]> alter table table_key drop index name_index;
Query OK, rows affected (0.01 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> alter table table_key drop index address_index;
Query OK, rows affected (0.01 sec)
Records: Duplicates: Warnings:
(dg1)root@127.0.0.1 [mytest]> alter table table_key add index name_address_index (name,address);
Query OK, rows affected (0.02 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where address='shanghai' and name='zhangsan';
+----+-------------+-----------+------+--------------------+--------------------+---------+-------------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+--------------------+--------------------+---------+-------------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | name_address_index | name_address_index | | const,const | | 100.00 | Using index condition |
+----+-------------+-----------+------+--------------------+--------------------+---------+-------------+------+----------+-----------------------+
row in set, warning (0.00 sec)
看看复合索引的长度,因为能全部使用到组合索引,所以是:2*(10)+2*(20)+2=42,下面将name字段允许为空,再来看看
(dg1)root@127.0.0.1 [mytest]> alter table table_key modify name char(10); (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where name='zhangsan' and address='shanghai';
+----+-------------+-----------+------+--------------------+--------------------+---------+-------------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+--------------------+--------------------+---------+-------------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | name_address_index | name_address_index | | const,const | | 100.00 | Using index condition |
+----+-------------+-----------+------+--------------------+--------------------+---------+-------------+------+----------+-----------------------+ row in set, warning (0.00 sec)
看看复合索引的长度,因为能全部使用到组合索引,所以是:2*(10)+1+2*(20)+2=43
(dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where name='zhangsan';
+----+-------------+-----------+------+--------------------+--------------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+--------------------+--------------------+---------+-------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | name_address_index | name_address_index | | const | | 100.00 | Using index condition |
+----+-------------+-----------+------+--------------------+--------------------+---------+-------+------+----------+-----------------------+
row in set, warning (0.00 sec)
那么我们来看看部分使用复合索引:2*(10)+1,将address设置为允许为空,再来看看
(dg1)root@127.0.0.1 [mytest]> alter table table_key modify address varchar();
Query OK, rows affected (0.04 sec)
Records: Duplicates: Warnings: (dg1)root@127.0.0.1 [mytest]> explain extended select * from table_key where name='zhangsan' and address='shanghai';
+----+-------------+-----------+------+--------------------+--------------------+---------+-------------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------+--------------------+--------------------+---------+-------------+------+----------+-----------------------+
| | SIMPLE | table_key | ref | name_address_index | name_address_index | | const,const | | 100.00 | Using index condition |
+----+-------------+-----------+------+--------------------+--------------------+---------+-------------+------+----------+-----------------------+
row in set, warning (0.00 sec) (dg1)root@127.0.0.1 [mytest]>
这时候key_len=2*(10)+1+2*(10)+2+1=44
总结:
1.整数类型,浮点数类型,时间类型的索引长度
NOT NULL=字段本身的字段长度
NULL=字段本身的字段长度+1,因为需要有是否为空的标记,这个标记需要占用1个字节
datetime类型在5.6中字段长度是5个字节
2.字符类型
varchr(n)变长字段且允许NULL = n * ( utf8=,gbk=,latin1=)+(NULL)+
varchr(n)变长字段且不允许NULL = n * ( utf8=,gbk=,latin1=)+ char(n)固定字段且允许NULL = n * ( utf8=,gbk=,latin1=)+(NULL)
char(n)固定字段且允许NULL = n * ( utf8=,gbk=,latin1=) 变长字段需要额外的2个字节(VARCHAR值保存时只保存需要的字符数,另加一个字节来记录长度(如果列声明的长度超过255,则使用两个字节),所以VARCAHR索引长度计算时候要加2),固定长度字段不需要额外的字节。而null都需要1个字节的额外空间,所以索引字段最好不要为NULL,因为NULL让统计更加复杂,并且需要额外的存储空间。这个结论在此得到了证实,复合索引有最左前缀的特性,如果复合索引能全部使用上,则是复合索引字段的索引长度之和,这也可以用来判定复合索引是否部分使用,还是全部使用。
MySQL执行计划explain的key_len解析的更多相关文章
- MySQL 执行计划explain详解
MySQL 执行计划explain详解 2015-08-10 13:56:27 分类: MySQL explain命令是查看查询优化器如何决定执行查询的主要方法.这个功能有局限性,并不总会说出真相,但 ...
- MySQL执行计划 EXPLAIN参数
MySQL执行计划参数详解 转http://www.jianshu.com/p/7134286b3a09 MySQL数据库中,在SELECT查询语句前边加上“EXPLAIN”或者“DESC”关键字,即 ...
- 【mysql】ICP下mysql执行计划的一次解析
mysql版本 [root@xxxx]# mysql --version mysql Ver 15.1 Distrib 5.5.52-MariaDB, for Linux (x86_64) using ...
- 如何看MySql执行计划explain(或desc)
简介 MySQL 提供了一个 EXPLAIN 命令, 它可以对 SELECT 语句进行分析, 并输出 SELECT 执行的详细信息, 以供开发人员针对性优化.EXPLAIN 命令用法十分简单, 在 S ...
- MySQL执行计划explain
一.简介 分析查询慢的原因,在查询语句前加explain即可.如: 二.输出格式 2.0 测试数据 # 表user_info CREATE TABLE `user_info` ( `id` bigin ...
- mysql执行计划
烂sql不仅直接影响sql的响应时间,更影响db的性能,导致其它正常的sql响应时间变长.如何写好sql,学会看执行计划至关重要.下面我简单讲讲mysql的执行计划,只列出了一些常见的情况, ...
- mysql执行计划介绍
简单讲讲mysql的执行计划,只列出了一些常见的情况,希望对大家有所帮助 烂sql不仅直接影响sql的响应时间,更影响db的性能,导致其它正常的sql响应时间变长.如何写好sql,学会看执行计划至 ...
- 解读EXPLAIN执行计划中的key_len(转)
原文:http://imysql.com/2015/10/20/mysql-faq-key-len-in-explain.shtml 导读 EXPLAIN中的key_len一列表示什么意思,该如何解读 ...
- Mysql执行计划说明
Mysql执行计划翻译: 官网原文请见http://dev.mysql.com/doc/refman/5.6/en/explain-output.html:5.6 EXPLAIN语句提供有关SELEC ...
随机推荐
- 【MST】P2323 [HNOI2006]公路修建问题
Description 给定 \(n\) 个点 \(m - 1\) 条无向边,每条边有两种边权,贵一点的和便宜一点的.要求至少选择 \(k\) 条贵边使得图联通且花费最大的边权值最小. Input 第 ...
- python基础2--字典
字典 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 语法: goods ...
- Java6的新特性
原文出处:xixicat 序 本文梳理了下java6的新特性,相对于java5而言,java6的特性显得少些,分量也不那么重,相当于java5是windows xp,java6有点像vista. 特性 ...
- 对硬盘进行分区时,GPT和MBR有什么区别?
在Windows 8或8.1中设置新磁盘时,系统会询问你是想要使用MBR还是GPT分区.GPT是一种新的标准,并在逐渐取代MBR. GPT带来了很多新特性,但MBR仍然拥有最好的兼容性.GPT并不是W ...
- Spyder之Object Inspector组件
Spyder之Object Inspector组件 最新版的Spyder已经把它修改为Help组件了. Quick access to documentation is a must for ever ...
- Swift控制手电筒操作(iOS)
手电筒是iphone的一个常用功能,最常用的操作就是turn on和turn off,下面我们来实现一个简单的手电筒操作程序:一个按钮来控制iphone手电筒的On和Off,并且按钮的text也做相应 ...
- <eq>标签
链接:http://document.thinkphp.cn/manual_3_2.html#taglib <eq name="menu.id" value="1& ...
- 【方法】纯jQuery实现星巴克官网导航栏效果
前言 大冬天的没得玩,只能和代码玩. 所以就无聊研究了一下星巴克官网,在我看来应该是基本还原吧~ 请各位大神指教! 官网效果图 要写的就是最上方的会闪现的白色条条 效果分析 1.在滚动条往下拉到一定距 ...
- 《区块链100问》第73集:达世币Dash是什么?
达世币诞生于2014年1月18日,匿名程度较比特币更高. 达世币有三种转账方式,一是像比特币一样的普通转账:二是即时交易.不需要矿工打包确认,就可以确认交易,几乎可以实现秒到:三是匿名交易.从区块链上 ...
- mogodb的安装与配置
下载:https://www.mongodb.com/https://www.mongodb.com/ 安装:一直next,中间选择custom,选择自己的安装路径,最后安装成功. 配置:打开安装好的 ...