【mysql索引】之前綴索引

第零步:簡單說一說

有時候需要索引很長的字符(例如BLOB,TEXT,或者很長的VARCHAR),這樣會使得索引又大又慢。

改良方法有:

1.改用哈希索引(這裏不講)。
2.使用字符串的前幾個字符作爲索引(即前綴索引)。

下面具體主要說第2種方法,主要思路就是選擇足夠長的前綴以保證較高的選擇性,同時又不能太長(造成空間浪費)。

所謂選擇性,是指不重複的索引數量除以總記錄數,範圍是(0,1],唯一索引之所以查詢效率高,是因爲它的選擇性等於1。

首先要做的是準備好足夠的數據來進行測試,最簡單的方法是:
我們剛安裝好MySQL的時候,會有一個叫sakila的數據庫,這個數據庫可以方便我們進行各種練習。

下面我們直接開始行動~用Navicat打開sakila數據庫(沒有Navicat?那就命令行use sakila吧)


第一步:建立測試表及其數據

-- 新建一個測試表city_demo,並把表city的數據複製過去
INSERT INTO city_demo SELECT city FROM city;
-- 把表city_demo自身的數據複製5次,即反覆執行下面這句語句5次
INSERT INTO city_demo SELECT city FROM city_demo;
-- 將表裏面的城市名隨機打亂(這一步生成的結果會與我之後展示的數據有差別,但並不影響分析)
UPDATE city_demo SET city = (SELECT city FROM city ORDER BY RAND() LIMIT 1);

第二步:計算合適的前綴索引長度

有兩種方法計算長度

方法一:

-- 查詢重複次數最多的10條完整城市名稱及其數量(圖1)
SELECT COUNT(*) cnt, city FROM city_demo GROUP BY city ORDER BY cnt DESC LIMIT 10;
-- 查詢重複次數最多的10條城市名稱(前3個字符)及其數量,可以發現:前3個字符的相同數量過大,不適合做前綴索引(圖2)
SELECT COUNT(*) cnt, LEFT(city,3) pref FROM city_demo GROUP BY pref ORDER BY cnt DESC LIMIT 10;
-- 查詢重複次數最多的10條城市名稱(前7個字符)及其數量,可以發現:前7個字符的相同數量和完整城市名稱很相近了,可以考慮作爲做前綴索引(圖3)
SELECT COUNT(*) cnt, LEFT(city,7) pref FROM city_demo GROUP BY pref ORDER BY cnt DESC LIMIT 10;

圖1:圖2:圖3:



方法二:

-- 計算出完整字符串的選擇性(圖4)
SELECT COUNT(DISTINCT city)/COUNT(*) FROM city_demo;
-- 計算各個前綴的選擇性(圖5),然後找出選擇性與圖4相近的
SELECT 
	COUNT(DISTINCT LEFT(city,3))/COUNT(*) pref3,
	COUNT(DISTINCT LEFT(city,4))/COUNT(*) pref4,
	COUNT(DISTINCT LEFT(city,5))/COUNT(*) pref5,
	COUNT(DISTINCT LEFT(city,6))/COUNT(*) pref6,
	COUNT(DISTINCT LEFT(city,7))/COUNT(*) pref7
FROM city_demo;

圖4:圖5:

不過pref4和pref5是一個陷阱,因爲它們看上去已經很接近完整字符串的選擇性了,但是我們可以用方法一來看一下:

-- 結果看圖6
SELECT COUNT(*) cnt, LEFT(city,4) pref4 FROM city_demo GROUP BY pref4 ORDER BY cnt DESC LIMIT 5;
-- 結果看圖7
SELECT COUNT(*) cnt, LEFT(city,5) pref5 FROM city_demo GROUP BY pref5 ORDER BY cnt DESC LIMIT 5;

圖6:圖7:

可以看出,前綴4和5的分佈還是不均勻的以Sant、South爲首的城市仍然比較多,結合方法一、二,可以建立長度爲7的前綴索引了


第三步:建立前綴索引

ALTER TABLE `city_demo` ADD INDEX `idx_city` (`city`(7)) USING BTREE ;
-- 或者這個也行
ALTER TABLE `city_demo` ADD KEY `idx_city` (`city`(7))
-- 又或者直接用Navicat可視化操作也行

前綴索引的缺點

MySQL中無法使用前綴索引進行ORDER BY和GROUP BY,也無法用來進行覆蓋掃描

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章