索引的原理與作用,各種書籍和網絡上的介紹可以說是鋪天蓋地,基本上主流資料庫系統的也都是一緻的。選擇索引字段的原則,比如外鍵字段、資料類型較小的字段、經常用于查詢或排序的字段、表關聯的字段等等,在此不做贅述。本人在工作中見到過很多人建立的索引,回想自己以前也會有理論知識空洞的體會,總感覺理論知識無法與具體的工作問題相比對。在此僅以工作學習中積累的一點經驗和問題場景整理以飨讀者。先把常見的注意事項整理如下:
索引應該建在選擇性高的字段上(鍵值唯一的記錄數/總記錄條數),選擇性越高索引的效果越好、價值越大,唯一索引的選擇性最高; 組合索引中字段的順序,選擇性越高的字段排在最前面; where條件中包含兩個選擇性高的字段時,可以考慮分别建立索引,引擎會同時使用兩個索引(在OR條件下,應該說必須分開建索引); 不要重複建立彼此有包含關系的索引,如index1(a,b,c) 、index2(a,b)、index3(a); 組合索引的字段不要過多,如果超過4個字段,一般需要考慮拆分成多個單列索引或更為簡單的組合索引;
最後需要提醒的是,不要濫用索引。因為過多的索引不僅僅會增加實體存儲的開銷,對于插入、删除、更新操作也會增加處理上的開銷,而且會增加優化器在選擇索引時的計算代價。
是以太多的索引與不充分、不正确的索引對性能都是毫無益處的。一言以蔽之,索引的建立必須慎重,對每個索引的必要性都應該經過仔細分析,要有建立的依據。
舉下面一個場景的例子,建立這樣的索引是有效的嗎?
再比如,該表最常使用的SQL場景有以下兩種類型,應該如何建立索引?
以執行計劃和邏輯IO的統計資料顯示,兩個場景的測試結果都是後者索引有明顯的效果,大家有興趣可以自己測試驗證一下。當然,生産環境遠比這些要複雜,各表的資料量及資料分布情況也會影響引擎的執行方式,引擎對索引選擇與要求也會不一樣,此處僅以簡單語句做示例進行說明。
組合索引查詢的各種場景:
組合索引 Index (A, B, C)
下面條件可以用上該組合索引查詢:
A>5
A=5 AND B>6
A=5 AND B=6 AND C=7
A=5 AND B=6 AND C IN (2, 3)
下面條件将不能用上組合索引查詢:
B>5 ——查詢條件不包含組合索引首列字段
B=6 AND C=7 ——理由同上
下面條件将能用上部分組合索引查詢:
A>5 AND B=2 ——當範圍查詢使用第一列,查詢條件僅僅能使用第一列
A=5 AND B>6 AND C=2 ——範圍查詢使用第二列,查詢條件僅僅能使用前二列
A=5 AND B IN (2, 3) AND C=2 ——理由同上
組合索引排序的各種場景:
組合索引 Index(A, B)
下面條件可以用上組合索引排序:
ORDER BY A ——首列排序
A=5 ORDER BY B ——第一列過濾後第二列排序
ORDER BY A DESC, B DESC ——注意,此時兩列以相同順序排序
A>5 ORDER BY A ——資料檢索和排序都在第一列
下面條件不能用上組合索引排序:
ORDER BY B ——排序在索引的第二列
A>5 ORDER BY B ——範圍查詢在第一列,排序在第二列
A IN(1,2) ORDER BY B ——理由同上
ORDER BY A ASC, B DESC ——注意,此時兩列以不同順序排序
索引合并的簡單說明:
資料庫能同時使用多個索引
SELECT * FROM TB WHERE A=5 AND B=6
能分别使用索引(A) 和 (B);
對于這個語句來說,建立組合索引(A,B) 更好;
最終是采用組合索引,還是兩個單列索引?主要取決于應用系統中是否存在這類語句:SELECT * FROM TB WHERE B=6
SELECT * FROM TB WHERE A=5 OR B=6
組合索引(A, B)不能用于此查詢(目前的資料庫也很智能,部分OR條件也能夠使用組合索引,但效果不是很穩定);
很明顯,分别建立索引(A) 和 (B)會更好;
删除無效的備援索引
TB表有兩個索引(A, B) 和 (A),對應兩種SQL語句:SELECT * FROM TB WHERE A=5 AND B=6 和 SELECT * FROM TB WHERE A=5
執行時,并不是WHERE A=5 就用 (A); WHERE A=5 AND B=6 就用 (A, B);
其查詢優化器會使用其中一個以前常用索引,要麼都用(A, B), 要麼都用 (A)。
是以應該删除索引(A),它已經被(A, B)包含了,沒有任何存在的必要。
附1,查詢指定表的資料量與索引定義情況:
附2,借助性能視圖,查詢資料表的SQL通路方式
附3,索引重建示例
補充:
Where條件中Or的兩組條件如果分别落在兩個資料表上,即使對應的字段都已建立索引,引擎也是無法使用索引的。如下SQL,此語句實際上僅傳回一條資料,但對于TRFKZL和TRHBZL來說,Oracle、SqlServer都是進行全表掃描。
按照建議更改SQL寫法,走索引查找,響應時間在1秒以内。當然,從原始語句的篩選條件也能夠感覺到怪怪的,根本上來講應該是個設計問題。