今天我們來聊一聊,普通索引和唯一索引的使用場景,以及為什么說推薦大家優先使用普通索引,盡量避免使用唯一索引。
前言
在使用MySQL的過程中,隨著表數據的逐漸增多,為了更快的查詢我們需要的數據,我們會在表中建立不同類型的索引。
今天我們來聊一聊,普通索引和唯一索引的使用場景,以及為什么說推薦大家優先使用普通索引,盡量避免使用唯一索引。
對于一個普通的二級索引,目的就是為了加速查詢,所以我們可能會為表中的某個字段或者某些字段,建立一個普通的二級索引。
而對于唯一索引來說,由于其唯一鍵約束的特性,有時我們會更多的賦予其業務含義。比如有一張存儲身份證號的表,為了保證身份證號的唯一性,我們會在身份證號字段上建立唯一索引。
那為什么說,不推薦大家使用唯一索引呢?
接下來,我們從查詢和更新兩方面分析一下唯一索引和普通索引的性能差距。
查詢性能
我們知道每個索引其實都是一棵二叉樹,所以我簡單畫了一個索引圖,不太好看,大家多多擔待。
給大家稍微解釋一下這張圖,不同顏色代表不同的數據頁,這里假設一個數據頁里面存放兩條數據。
我們知道MySQL磁盤與內存交互是通過一個叫做數據頁的單位,每個數據頁默認的大小是16K。
在一棵樹上,只有葉子節點才會真正的存放數據,非葉子節點存放的是每個下級數據頁中最小的索引字段以及指向下級數據頁的指針。
對于主鍵索引,葉子節點存放的是一行真正的數據,而對于二級索引來說,在葉子節點存儲的是索引字段以及對應的主鍵id。
好了,下面我們分析一下,普通二級索引和唯一索引是如何查數據的?
以一個簡單的查詢sql為例:select id from t where m=103;
1,MySQL從根節點出發,通過二分法判斷m=103大于100小于104,所以會找到根節點中100對應的數據頁100-102;
2,在100-102的數據頁上,由于103大于102,所以會找到102對應的102-103的數據頁;
3,在這個數據頁上,找到了m=103的記錄,并獲取到了要查詢的id字段。
對于普通的二級索引來說,找到第一條m=103的記錄之后,會繼續向后查找,在104-105這個數據頁中判斷是否還有符合m=103條件的記錄,如果沒有則結束查詢。
而對于唯一索引來說,由于其唯一性約束,所以在查找到第一條記錄之后,就結束了查找。
可以看到,二者的差別就在于是否繼續查到下一條。
那這兩者有多大的性能差距呢?答案是幾乎沒有。
我們知道,MySQL的數據是以頁為單位存放的,以一個int類型的二級索引為例,一個int占4個字節,加上MySQL的頭信息6個字節,相當于10個字節。
那么一個16k的頁上能存放多少記錄呢?
16*1024/10 = 1638。也就是說,一個數據頁就可能放下1600多條記錄。那么我們在查詢數據時,會把整個數據頁都加載進內存,此時對于普通二級索引判斷下一個記錄的操作所需的消耗是非常非常小的。
可以說,從查詢方面來看,普通二級索引和唯一索引的性能基本是相當的。
更新性能
唯一索引和普通二級索引的性能差距主要體現在更新操作上。
對于MySQL來說,更新一條語句的邏輯是首先讀到要更新的記錄,如果這個記錄沒有在內存里,就先加載到內存。然后執行更新的語句,之后再把變更的數據刷新到磁盤中。
但是,對于MySQL來說,把數據從磁盤讀到內存涉及到隨機IO,是成本非常高的一種操作。
如果每次更新數據都要這么來一次的話,高性能這個指標恐怕很難保證。
所以,設計MySQL的大神們引入了一個叫做change buffer的東西。
change buffer是一種可以持久化的緩存數據,當我們要更新數據時,如果要更新的數據不存在于內存,此時并不需要把數據從磁盤加載到內存,而是將更新操作記錄在change buffer中,更新操作就算完成了。
當下次要讀取這些數據時,會把讀到的數據和change buffer進行合并,或者叫merge。
通過change buffer,更新操作就不需要去讀磁盤了,全程都是內存操作,性能自然可以得到極大的提升。
但是!但是問題又來了!
change buffer只對普通二級索引有效,對于唯一索引是沒有效果的。
為什么呢?
因為在更新一條記錄時,我們需要檢查索引的唯一性約束。
如何檢查呢?自然首先要把數據從磁盤加載到內存里面才能進行判斷。
可是如果都已經把數據加載到內存里,再去使用change buffer不就顯得多此一舉了。
所以,唯一索引不能,也沒必要去使用change buffer來提升性能了。
由于對唯一索引的更新涉及到讀磁盤這個隨機IO操作,性能自然也是比不上普通二級索引了,這就是推薦大家優先使用普通二級索引的原因了。
經過對比,大家也可以看到,這兩種索引在查詢上性能基本是一致的,其性能差距主要體現在更新操作上。
其實即便是大家有一些特殊的業務需要,比如存放唯一的身份證號等,還是建議大家通過業務層去約束。
總的來說,普通的二級索引比唯一索引帶來的收益要更大。