淺談sql索引

索引是什麼

假如你手上有一個你公司的客戶表,老闆說找什麼客戶你就得幫他找出來。mysql

客戶很少的時候,你拿着手指一行一行滑,費不了多少時間就能找到。sql

後來公司作大了,客戶愈來愈多,好幾頁的客戶,你發現,一行一行滑真的好累啊,最主要找慢了還得挨老闆叼。數據庫

他媽的,吃力不討好。併發

那咋辦?高併發

我相信這麼聰明的你不會坐以待斃的。性能

你可能會本身作一些記錄,好比拿個小本本寫上,mysql索引

28歲的客戶在第一頁
29歲的客戶在第二頁指針

或者code

姓張的客戶在第二頁
姓李的客戶在第三頁和第四頁blog

固然這些要根據那張客戶表的實際狀況來。

這樣子,下次老闆叫你找29歲的客戶,你就一會兒翻到第二頁,一會兒就找到了,輕鬆又漂亮地解決了問題。

這麼機智地解決了問題,當上ceo,迎娶白富美就指日可待了。

好了,美好故事到此就結束了。

真實的狀況是怎麼樣的呢?

真實的狀況就是數據庫就是故事中的你,你就是故事中的老闆,故事中的小本本,就是我們今天要講的索引。

索引的特色

那麼從這個故事中能夠看出索引有什麼特色呢?

爲了提升查找效率而創建

若是你不給數據庫加索引的話,多數狀況下,它就真的是一行行找,效率極低。

數據量少的時候不須要索引

但數據量少的時候,也不必建索引,你想一想啊,數據量少的時候,你一會兒就找到了,速度比你去翻小本本時間可能還要快點,就不要浪費一個小本本了。
MySQL的索引本質也是一張表的,創建索引也須要相應的空間。

索引是創建在表的數據上的

上面的故事裏我也說了,小本本的內容要根據你表裏的實際狀況來的。
這樣的話,若是創建了索引,就要注意兩個點:

  1. 不要實際刪除數據。
    假如你有批客戶鬧掰了,你一輩子氣,把客戶表中那一整頁都撕了。
    那你下次按照【31歲的客戶在第20頁】這個規則去找,可是前面的就被你撕了,如今31歲的客戶就提早了幾頁,你數到第20頁,發現找不到,人都傻了。
    MySQL也是這樣的,若是刪除數據,會致使按照索引查找的數據不會在原先的位置上。

  2. 頻繁更新的字段不要創建索引。
    假設用戶的年齡每天變,那最好也不要記在小本本上了,不然你天天都要去更新小本本,今天是【31歲的客戶在第20頁】,明天就要改爲【32歲的客戶在第20頁】了。
    MySQL也是這樣的,若是創建索引的字段頻繁更新,這樣便會致使以前創建的索引須要頻繁更新。

MySQL索引分類

人家MySQL創建索引的方式比咱們記小本本的方式要聰明有效率地多了。
你能夠看到我上面作小本本的方式都是根據表中的某一列來的,好比

【31歲的客戶在第20頁】這個是根據客戶的年齡這一列來作的;
【姓李的客戶在第三頁和第四頁】這個使用客戶的名字這一列來作的。

在MySQL中,咱們也只是須要告訴MySQL用哪些列來作索引便可,而後接下來的事他就會本身作。
我們創建的索引呢,根據使用列的狀況不一樣,能夠分類以下:

  • 單值索引:即一個索引只包含單個列。一個表能夠有多個單列索引。

  • 惟一索引:索引列的值必須惟一,但容許有空值。

  • 複合索引:即一個索引包含多個列。

假如如今有一個people表,內有字段id(主鍵不須要作索引),name,age,phone_number(電話號碼)那麼:

  • 單值索引:能夠單獨用nameage作一個索引,任何一個字段均可以。這樣的索引能夠作多個。
  • 惟一索引:和單值索引同樣,但作索引的該字段必須惟一,好比你肯定people表中phone_number的值惟一的話,那麼即可以在上面創建惟一索引。
  • 複合索引:能夠用(name,age)(age,phone_number)(name,age,phone_number)作一個索引。

建議:創建複合索引,且一個表不要超過5個索引。

基本語法

  • 建立(若是加上UNIQUE則建立惟一索引):

    CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length));

    ALTER mytable ADD [UNIQUE] INDEX[indexName] ON (columnname(length));

  • 刪除:

    DROP INDEX [indexName] ON mytable;

  • 查看:

    SHOW INDEX FROM table\G

MySQL索引結構

上面的索引創建好後,MySQL是按照什麼樣的策略去查找數據的呢。
有幾種結構,下面講的是比較經常使用的BTree結構。

  • 圖片介紹:

    如圖一顆B+樹,淺藍色表示磁盤塊,每一個磁盤塊包括幾個數據項(深藍色)和指針(黃色)。

    如磁盤塊1包括數據項17和35,包含指針P一、P二、P3;P1表示小於17的磁盤塊,P2表示在17-35之間的磁盤塊,P3表示大於35的磁盤塊。

    真實的數據只存在於葉子節點,非葉子節點不存儲真實數據,只存儲指引搜索方向的數據項。

    如1七、35並不真實存在數據表中。

  • 查找過程(以上圖查找數據項29):

    首先把磁盤塊1由磁盤加載到內存,此時發生一次IO;在內存中用二分查找肯定29在17和35之間,鎖定磁盤塊1的P2指針,由於內存時間很是短(相比磁盤的IO)能夠忽略不計。

    將磁盤塊1的P2指向的磁盤塊3由磁盤加載到內存,發生第二次IO;肯定29在26和30之間,指向磁盤塊3的P2指針。

    將磁盤塊3的P2指針指向的磁盤塊8加載到內存,發生第三次IO,同時內存中作二分查找找到29。

    查詢結束,總計三次IO。

  • 真實的狀況是:3層的B+樹能夠表示上百萬的數據,若是上百萬的數據查找只須要3次IO,性能提升將是巨大的,若是沒有索引,每一個數據項都要發生一次IO,那麼總共須要上百萬次IO。

  • 總結:減小IO次數能夠減小查詢時間,提升性能,那麼怎麼減小IO次數?
    答案:增長樹的廣度而非深度。B+樹的葉子節點能夠多。

創建索引的時機

哪些狀況須要建立索引
  • 主鍵自動創建惟一索引
  • 頻繁做爲查詢條件的字段應該建立索引
  • 查詢中與其餘表關聯的字段,外鍵關係創建索引
  • 頻繁更新的字段不適合建立索引 -- 由於每次更新不僅更新記錄還會更新索引
  • Where裏用不到的字段的不建立索引
  • 單鍵/組合索引的選擇問題 -- 在高併發下傾向建立組合索引
  • 查詢中排序的字段 -- 排序字段若經過索引去訪問將大大提升排序速度
  • 查詢中統計或者分組字段
哪些狀況不須要建立索引
  • 表記錄太少 -- mysql300w左右就能夠考慮建索引了
  • 常常增刪改的表 -- 由於索引要跟着更新
  • 數據重複且分佈平均的表字段 -- 能夠用(該字段不一樣的數據的數量)/(該字段總的數據量),值越接近1,說明不怎麼重複,越有建索引的價值。
相關文章
相關標籤/搜索