http://blog.csdn.net/qsc0624/article/details/51335632
大家應該知道InnoDB單列索引長度不能超過767bytes,聯合索引還有一個限制是長度不能超過3072。
- mysql> CREATE TABLE `tb` (
- -> `a` varchar(255) DEFAULT NULL,
- -> `b` varchar(255) DEFAULT NULL,
- -> `c` varchar(255) DEFAULT NULL,
- -> `d` varchar(255) DEFAULT NULL,
- -> `e` varchar(255) DEFAULT NULL,
- -> KEY `a` (`a`,`b`,`c`,`d`,`e`)
- -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
可以看到,由於每個字段占用255*3, 因此這個索引的大小是3825>3072,報錯。
為什么3072
我們知道InnoDB一個page的默認大小是16k。由於是Btree組織,要求葉子節點上一個page至少要包含兩條記錄(否則就退化鏈表了)。
所以一個記錄最多不能超過8k。
又由於InnoDB的聚簇索引結構,一個二級索引要包含主鍵索引,因此每個單個索引不能超過4k (極端情況,pk和某個二級索引都達到這個限制)。
由於需要預留和輔助空間,扣掉后不能超過3500,取個“整數”就是(1024*3)。
單列索引限制
上面有提到單列索引限制767,起因是256×3-1。這個3是字符最大占用空間(utf8)。但是在5.5以后,開始支持4個字節的uutf8。255×4>767, 於是增加了一個參數叫做 innodb_large_prefix。
這個參數默認值是OFF。當改為ON時,允許列索引最大達到3072。
可以看到默認行為是建表成功,報一個warning,並且將長度階段為255。
注意要生效需要加row_format=compressed或者dynamic 。
如果確實需要在單個很大的列上創建索引,或者需要在多個很大的列上創建聯合索引,而又超過了索引的長度限制,解決辦法是在建索引時限制索引prefix的大小:
例如:create index yarn_app_result_i4 on yarn_app_result (flow_exec_id(100), another_column(50));
這樣,在創建索引時就會限制使用的每個列的最大長度。如上的例子中,在創建聯合索引時,最多使用列flow_exec_id中前100個字符創建索引,最多使用another_column中前
50個字符創建索引。這樣子,就可以避免索引長度過大的問題。
最后,我想說一句。我們在設計數據庫時,最好不要在一個可能包含很長字符串的列上創建索引,尤其是當這個列中的字符串都很長時。如果在這類列上創建了索引,那么在創建索引時以及根據索引查詢時,都會浪費很多時間在計算和存儲上。有經驗的設計人員應該不會這樣設計數據庫。