說明
之前對Postgres/GP的索引測試見GP索引調優測試–基本篇.md和GP索引調優測試–排序篇,此文給出原理解釋。
原理
建議先閱讀“深入理解計算機系統(原書第2版)的第6章 存儲器層次結構”,再瞭解B樹,最後閱讀數據庫索引原理及優化,可以對索引的原理有很清楚的瞭解。
這裏給出使用索引和不使用索引時,查詢時間的複雜度,
查詢類型 | 無索引複雜度 | 有索引複雜度 |
---|---|---|
特定數據(= ) |
O(n) (注:n次順序讀取) | O(lgn+1) (注:lgn次查找+1次隨機讀取) |
特定範圍(range ) |
O(n)(注:n次順序讀取) | O( lgn+m)(注:lgn次查找+m次隨機讀取,m爲range的範圍) |
排序 | O(nlgn) (注:這裏認爲排序的複雜度爲nlgn) | O(lgn+n)(注:lgn次隨機讀取找到第一個值,之後往後讀取) |
解釋
故之前的測試結果可以給出解釋,
1. 查找特定數據走索引,而且很快
隨機讀取雖然花費時間比較長,但次數很少,故走索引
2. 特定範圍數據,數據量小時走索引,大時並不走
數據量小時m比較小,故走索引;數據量大時,比如爲n,此時lgn+n>n,故不走索引(注意,複雜度中n爲常量,m纔是變量)!
3. 排序走索引
有索引的複雜度要低一些
附錄
查詢大量特定數據
實際上,在上述查找特定數據時,也可能是不走索引的。比如,來自高效使用PostgreSQL索引的一個例子,
從表中檢索到的行數可以基於特定的常數值的查詢檢索而變化。(我注:即不同的常量值,會導致不同的結果行數)。因此,例如,查詢計劃器對於查詢select * from foo where bar = 1使用索引可能是正確的,但對於查詢select * from foo where bar = 2卻可能不使用索引,這發生於對於bar值爲2的行有比較多的話。發生這種情況時,順序掃描實際上是最有可能比索引掃描快得多,因此,查詢計劃器實際上是判斷正確的,這時順序掃描的性能代價相比索引掃描更低。
即,實際上查詢特定值的複雜度分別爲O(n)(注:n次順序讀取)
,O( lgn+m)(注:lgn次隨機讀取,m爲該值重複的次數)
,故當該值重複較多時並不走索引,與範圍查詢類似。更深入的分析見爲什麼我在Sql Server上創建的索引用不上? - 知乎。
更多關於不走索引的情況分析見筆記–索引失效情況分析.md。
排序大量數據
實際上參見筆記–Postgres索引測試–基本篇.md,針對排序,在大量數據下使用索引反而可能變慢,參見11.4. 索引和ORDER BY,如下,
對於一個需要掃描表的大部分的查詢, 明確的排序可能要比使用索引快的多,因爲它使用順序存取模式所以需要較少的磁盤I/O。 當只需要獲取幾行時,索引是更有效的。