數據庫中的索引

  很多朋友在操作數據庫的時候經常會用到索引,通過索引獲取數據的確可以讓這個sql語句運行的更快,但是很多人並不知道爲什麼使用索引會變快,更不用說索引的一些弊端了,今天主要介紹一下索引。


  1. 索引結構:

      首先聲明,索引有很多種,B樹索引、hash索引、位圖索引、文本索引等等,這裏僅介紹工作中用的最多的B樹索引。

      其實B樹索引就像名字所描述的那樣,就是一棵平衡樹(balance tree,當然肯定不止這麼簡單),這裏以mysql的innodb存儲引擎爲例,平衡樹非葉節點存儲的是(key,address)、即索引值以及下一層某塊地址這樣的數據結構;而葉子節點在非主鍵索引中存儲的是(key, primary key)、即索引值以及對應的主鍵值這樣的鍵值對結構,在主鍵索引中存儲的是(primary key, content)、即主鍵值以及這一行內容。

    以下是一個兩層索引的結構圖:(紅色代表一個數據塊即數據庫IO最小單元,藍色代表上面討論   的鍵值對)

    wKiom1heoG_hv42RAAA55yDl9CY305.png-wh_50


    以一個數據塊16k,一個非(primary key, content)類型的鍵值對50+4 bytes 爲例,則一個數   據塊可以存儲約(1600/50)=300個這樣的鍵值對結構,那麼到了第二層,就可以存儲(300*300)   =9w條被索引數據對應的主鍵信息,到了第三層就是(300*300*300)=2700w,以此類推,飛速增長。

    當然隨着數據的增減,rdbms會自動維護索引,這也是爲什麼索引對查詢有利,對增刪改有弊的原   因。


 2.簡單比較:

     以上面的索引爲例,現在假設有一張9w行的表,一個非主鍵索引就佔有約300個數據塊,那麼這    裏不妨假設主鍵索引佔有600個數據塊(包括葉節點的所有數據,當然實際生產應該只會更大)。

     在oracle中,lotp系統緩存命中率低於95%通常都會建議增加內存,因此這裏假設所有的索引數    據以及表數據都存放在內存中了。

   場景一:在有索引列的情況下,獲取某一行數據

    在這種情況下,如果全表掃描,則需要掃描約(1+600)/2=300個數據塊;如果根據上面的索引    則需要掃描2(根據索引列獲取主鍵)+2(不妨假設這裏主鍵索引也只有兩層)=4個數據塊,理想    情況下後者只用前者4/300=1/75的時間。

   場景二:全表掃描

    在這種情況下,若果全表掃描,則掃描600個數據塊;如果根據上述索引則需要掃描4*9w=36w個    數據塊,此時後者時間遠大於前者!

     在這個場景下,通過計算600/4=125,可以知道如果通過索引獲取的數據超過125行那麼利用索    引的效率還不如全表掃描,在oracle RBO的年代裏面可能真的就會不管成本有索引就用索引,但是    現在oracle已經將優化策略改成CBO了,在掃描行太多的情況下會選擇全表掃描,mysql是怎麼處理    的還不清楚。


3.索引利弊

 1)索引是隨機讀的

    如果筆者沒有記錯,計算機組成原理中,cache會將內存中臨近的數據cache到CPU中,雖然內存    跟cache的速度相差沒有內存與磁盤那麼明顯,但是隨機的內存讀,肯定還是沒有將數據全部cache    到CPU快的。


 2)索引並不適合大量查詢

     就像上面的例子,如果掃描行超過125行那麼還不如全表掃描,雖然在工作中會不一樣,但希望    大家做範圍掃描的時候多注意一下,不要一次掃描的行太多。


 3)索引耗費空間

    其實索引說白了就是一個只有兩列的數據表,在innodb中有一列已經確定了就是主鍵(即使沒    有指定主鍵,mysql也會自己創建一個),這也是爲什麼主鍵不要太長的原因之一,對於一個有n個    B樹索引的表,主鍵要存儲n+1次,被索引的列也要多存儲一次。


4.補充

   其實索引要考慮的東西還有很多,比如聚合因子、鎖相關信息等等,希望大家有空的時候自己在下面多多研究。

                        2016.12.24

                        肯草在深圳


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