今天丁原問我mysql執行計劃中的key_len是怎麼計算得到的,當時還沒有注意,在高性能的那本書講到過這個值的計算,但是自己看執行計劃的時候一直都沒有太在意這個值,更不用說深討這個值的計算了:
ken_len表示索引使用的字節數,根據這個值,就可以判斷索引使用情況,特別是在組合索引的時候,判斷所有的索引字段都被查詢用到。
在查看官方文檔的時候,也沒有發現詳細的key_len的計算介紹,後來做了一些測試,在諮詢了丁奇關於變長數據類型的值計算的時候,突然想到innodb 行的格式,在這裏的計算中有點類似,總結一下需要考慮到以下一些情況:
(1).索引字段的附加信息:可以分爲變長和定長數據類型討論,當索引字段爲定長數據類型,比如char,int,datetime,需要有是否爲空的標記,這個標記需要佔用1個字節;對於變長數據類型,比如:varchar,除了是否爲空的標記外,還需要有長度信息,需要佔用2個字節;
(備註:當字段定義爲非空的時候,是否爲空的標記將不佔用字節)
(2).同時還需要考慮表所使用的字符集,不同的字符集,gbk編碼的爲一個字符2個字節,utf8編碼的一個字符3個字節;
先看定長數據類型的一個例子(編碼爲gbk):
root@test 07:32:39>create table test_char(id int not null ,name_1 char(20),name_2 char(20),
-> primary key(id),key ind_name(name_1,name_2))engine=innodb charset=gbk;
root@test 07:33:55>insert into test_char values(1,’xuancan’,'taobaodba’);
root@test 07:34:55>explain select * from test_char where name_1=’xuancan’\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test_char
type: ref
possible_keys: ind_name
key: ind_name
key_len: 41
ref: const
rows: 1
Extra: Using where; Using index
key_len=41=20*2+1(備註:由於name_1爲空,isnull的標記被打上,需要計算1個字節)
root@test 07:35:31>explain select * from test_char where name_1=’xuancan’ and name_2=’taobaodba’\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test_char
type: ref
possible_keys: ind_name
key: ind_name
key_len: 82
ref: const,const
rows: 1
Extra: Using where; Using index
key_len=82=20*2+20*2+1+1(備註:由於name_1,name_2兩列被使用到,但兩列都爲爲空,需要計算2個字節)
變長數據類型(gbk編碼):
root@test 08:30:51>create table test_varchar(id int not null ,name_1 varchar(20),name_2 varchar(20),
-> primary key(id),key ind_name(name_1,name_2))engine=innodb charset=gbk;
root@test 08:37:51>insert into test_varchar values(1,’xuancan’,'taobaodba’);
root@test 08:38:14>explain select * from test_varchar where name_1=’xuancan’\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test_varchar
type: ref
possible_keys: ind_name
key: ind_name
key_len: 43
ref: const
rows: 1
Extra: Using where; Using index
key_len=43=20*2+1+2(備註:由於爲name_1字段定義爲空,所以需要計算1,;同時由於是變長字段varchar,所以需要加上2)
root@test 08:38:46>alter table test_varchar modify column name_1 varchar(20) not null;
Query OK, 1 row affected (0.52 sec)
Records: 1 Duplicates: 0 Warnings: 0
root@test 08:42:11>explain select * from test_varchar where name_1=’xuancan’\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test_varchar
type: ref
possible_keys: ind_name
key: ind_name
key_len: 42
ref: const
rows: 1
Extra: Using where; Using index
key_len=42=20*2+2(備註由於name_1字段修改爲not null之後,isnull的標記鎖佔用的字節釋放掉,但是變長字段長度所佔用的2個字節沒有釋放);
上面是測試gbk編碼的測試,同時也可以測試一下其他編碼的key_len計算。
http://hidba.org/?p=404