【mysql索引】之字首索引
阿新 • • 發佈:2019-01-29
第零步:簡單說一說
有時候需要索引很長的字元(例如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,也無法用來進行覆蓋掃描