1. 程式人生 > >淺談sql索引

淺談sql索引

# 索引是什麼 假如你手上有一個你公司的客戶表,老闆說找什麼客戶你就得幫他找出來。 客戶不多的時候,你拿著手指一行一行滑,費不了多少時間就能找到。 後來公司做大了,客戶越來越多,好幾頁的客戶,你發現,一行一行滑真的好累啊,最主要找慢了還得挨老闆叼。 他媽的,吃力不討好。 那咋辦? 我相信這麼聰明的你不會坐以待斃的。 你可能會自己做一些記錄,比如拿個小本本寫上, > 28歲的客戶在第一頁 > 29歲的客戶在第二頁 或者 > 姓張的客戶在第二頁 > 姓李的客戶在第三頁和第四頁 當然這些要根據那張客戶表的實際情況來。 這樣子,下次老闆叫你找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(電話號碼)那麼: - 單值索引:可以單獨用name**或**age做**一個**索引,任何一個欄位都可以。這樣的索引可以做多個。 - 唯一索引:和單值索引一樣,但做索引的該欄位必須唯一,比如你確定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結構。 ![](https://img2020.cnblogs.com/blog/1573343/202101/1573343-20210115175127141-1799040943.png) - 圖片介紹: 如圖一顆B+樹,淺藍色表示磁碟塊,每個磁碟塊包括幾個資料項(深藍色)和指標(黃色)。 如磁碟塊1包括資料項17和35,包含指標P1、P2、P3;P1表示小於17的磁碟塊,P2表示在17-35之間的磁碟塊,P3表示大於35的磁碟塊。 **真實的資料只存在於葉子節點,非葉子節點不儲存真實資料,只儲存指引搜尋方向的資料項。** 如17、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,說明不怎麼重複,越有建索引的價值。 # 最後 其實索引只是一個優化資料庫查詢速度的一個工具,資料量少的時候完全可以不用,​他也有缺點,一旦你對資料表有修改,那麼相應的索引也要做修改操作。 而且關於索引,難點在於針對一個具體的表去做出最合適的索引,這不只要看你表裡有什麼內容,更多要看你的業務,你的業務會經常根據哪些關鍵詞查詢,這個更考驗一個人的能力吧。 最後祝各位​,早日當上CEO,迎娶白富美