MySQL索引選擇及規則整理


索引選擇性就是結果個數與總個數的比值。

用sql語句表示為:

SELECT COUNT(*) FROM table_name WHERE column_name/SELECT COUNT(*) FROM table_name

 一般來說(例如書 “SQL Tuning“),如果選擇性超過 20% 那么全表掃描比使用索引性能更優。

但MySQL是沒有計算索引的選擇性的,只是預測邏輯IO操作的數量,因此對於MySQL索引要慎重選擇。

 

舉個栗子,tinyint類型的列,用以保存性別,就算用上“保密”和“變性”2項,選擇性也最小也才25%,因此也就沒有設置索引的必要了。

 

以下是整理出來的規則,以供參考:(由於很多實際項目都是查詢操作占了絕大部分,因此不必太過呆板)

1、選擇維度高的列

2、選擇 where,on,group by,order by 中出現的列

3、選擇較小的數據列,這樣的索引文件更小,同時可裝載更多的索引鍵

4、為較長的字符串使用前綴索引

5、組合索引能減低索引文件的大小,使用速度也優於多個單列索引

6、切勿濫用索引,因為除了磁盤空間的開銷外,每次增刪改都需要重新建立索引

7、索引不會包含有NULL值的列(若組合索引包含NULL值的列則整個組合索引無效)

 

另外,使用索引應當盡量避免 “OR” 、“否定查詢” 、“模糊查詢”、“NOT IN”、“<>” 等操作!

 

注意:前綴索引和組合索引是建立索引的一種技巧,並非索引類型。

 

組合索引

假設test表中有a,b,c三個列。

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"

以下則用不到索引:

SELECT * FROM test WHERE b="1" AND c="2" SELECT * FROM test WHERE c="1"

因此組合索引有一定優勢,但在使用上需謹慎。

 

前綴索引

MySQL 前綴索引能有效減小索引文件的大小,提高索引的速度。但是前綴索引也有它的壞處:MySQL 不能在 ORDER BY 或 GROUP BY 中使用前綴索引,也不能把它們用作覆蓋索引(Covering Index)。

語法如下:

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個字符的選擇性又是多少

SELECT COUNT(DISTINCT LEFT(family_name,1))/COUNT(*) FROM user;

假設這里得到的結果是0.532,和整列的選擇性出入太大,不可取,繼續:

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的模式缺省是忽略大小寫的!

另外,“_”代表一個字符,“%”代表任意多個字符!

 

PS:如存在錯誤或不恰當之處,請不吝指正!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM