索引選擇性就是結果個數與總個數的比值。
用sql語句表示爲:java
SELECT COUNT(*) FROM table_name WHERE column_name/SELECT COUNT(*) FROM table_name
通常來講(例如書 「SQL Tuning「),若是選擇性超過 20% 那麼全表掃描比使用索引性能更優。
但MySQL是沒有計算索引的選擇性的,只是預測邏輯IO操做的數量,所以對於MySQL索引要慎重選擇。
舉個栗子,tinyint類型的列,用以保存性別,就算用上「保密」和「變性」2項,選擇性也最小也才25%,所以也就沒有設置索引的必要了。sql
假設test表中有a,b,c三個列。bash
ALTER TABLE test ADD INDEX abc(a,b,c);
至關於分別創建了
a,b,c
a,b
a
這樣的3組索引,也是「最左前綴」這個規則的結果。
舉個使用該組合索引的栗子:性能
SELECT * FROM test WHERE a="1" AND b="2" SELECT * FROM test WHERE a="1"
如下則用不到索引:ui
SELECT * FROM test WHERE b="1" AND c="2" SELECT * FROM test WHERE c="1"
所以組合索引有必定優點,但在使用上需謹慎。spa
MySQL 前綴索引能有效減少索引文件的大小,提升索引的速度。可是前綴索引也有它的壞處:MySQL 不能在 ORDER BY 或 GROUP BY 中使用前綴索引,也不能把它們用做覆蓋索引(Covering Index)。
語法以下:code
ALTER TABLE table_name ADD KEY column_name(prefix_length);
創建前綴索引的關鍵在於"prefix_length"這個參數,而且前綴索引的選擇性上也有一點特殊。
前綴索引的選擇性公式爲:SELECT COUNT(DISTINCT column_name)/COUNT(*) FROM table_name
繼續舉栗子!
如今有個user表,列 family_name varchar(50) 保存的是英文姓氏(我也想用中文姓名來舉例,可是不大適合,看下去就明白了。。。)
要取得設置前綴索引最理想的"prefix_length",咱們首先要取得整列的選擇性,以下:索引
SELECT COUNT(DISTINCT family_name)/COUNT(*) FROM user;
假設這裏獲得值是0.188。
而後咱們繼續去看看該列前1個字符的選擇性又是多少string
SELECT COUNT(DISTINCT LEFT(family_name,1))/COUNT(*) FROM user;
假設這裏獲得的結果是0.532,和整列的選擇性出入太大,不可取,繼續:it
SELECT COUNT(DISTINCT LEFT(family_name,2))/COUNT(*) FROM user; SELECT COUNT(DISTINCT LEFT(family_name,3))/COUNT(*) FROM user; ...
假設直接到「prefix_length」爲5時,獲得的值爲0.189,很是接近!
而取6時獲得的值爲0.18891,這個選擇性和5並無太大的誤差。
再結合減小索引文件大小的這個思路
「prefix_length」值設置爲5纔是此處設置前綴索引的最優方案!
選擇性講完,還得再講清楚這個前綴索引該怎麼用!
書接上面的栗子~
正確的用法以下:
SELECT * FROM user WHERE family_name LIKE "lee%"; SELECT * FROM user WHERE family_name LIKE "david%";
如下則用不上該索引:
SELECT * FROM user WHERE family_name LIKE "_ee%"; SELECT * FROM user WHERE family_name LIKE "%en%"; SELECT * FROM user WHERE family_name LIKE "%ar%";
注意:SQL的模式缺省是忽略大小寫的! 另外,「_」表明一個字符,「%」表明任意多個字符!