一:概述
- 如果業務代碼已經保證了不會寫入重復的身份證號。
- 從性能的角度考慮,你會為這個身份證號,選擇唯一索引還是普通索引呢?選擇的依據是什么呢?
- 這就要從他們的執行過程看起。
二:唯一索引 和 普通索引 的查詢過程?
- 例如
- 執行查詢的語句是 select id from T where k=5
- 查詢語句在索引樹上查找的過程
- 先是通過 B+ 樹從樹根開始,按層搜索到葉子節點,定位數據頁。
- 數據頁內部通過二分法來定位記錄。
- 對於普通索引來說
- 查找到滿足條件的第一個記錄 k=5 后,需要查找下一個記錄。
- 直到碰到第一個不滿足 k=5 條件的記錄。
- 對於唯一索引來說
- 由於索引定義了唯一性,查找到第一個滿足條件的記錄后,就會停止繼續檢索。
三:唯一索引 和 普通索引 的查詢性能比較?
- 性能之差 微乎其微
- 原因
- InnoDB 的數據是按數據頁為單位來讀寫的。
- 當需要讀一條記錄的時候,並不是將這個記錄本身從磁盤讀出來,而是以頁(InnoDB 中,每個數據頁的大小默認是 16KB)為單位,將其整體讀入內存。
- 那么,對於普通索引來說,要多做的那一次“查找和判斷下一條記錄”的操作,就只需要一次指針尋找和一次計算。
- 當然,如果 k=5 這個記錄剛好是這個數據頁的最后一個記錄,那么要取下一個記錄,必須讀取下一個數據頁,這個操作會稍微復雜一些。
- 但是,對於整型字段,一個數據頁可以放近千個 key,因此出現這種情況的概率會很低。
- 所以,我們計算平均性能差異時,仍可以認為這個操作成本對於現在的 CPU 來說可以忽略不計。
四:既然在查詢性能一致,那么他們的更新性能呢,在討論更新之前,我們來看下 InnoDB 對於更新的優化 Chage Buffer.
五:Change Buffer
- 原理(當需要更新一個數據時)
- 如果數據頁在內存中就直接更新。
- 如果數據頁不在內存中。
- 在不影響數據一致性的前提下,InooDB 會將這些更新操作緩存在 change buffer 中,這樣就不需要從磁盤中讀入這個數據頁了。
- 在下次查詢需要訪問這個數據頁的時候,將數據頁讀入內存,然后執行 change buffer 中與這個頁有關的操作。
- 通過這種方式就能保證這個數據邏輯的正確性。
- Change buffer 什么時候會真正的更新 ?
- 雖然名字叫作 change buffer,實際上它是可以持久化的數據。
- 也就是說,change buffer 在內存中有拷貝,也會被寫入到磁盤上。
- 將 change buffer 中的操作應用到原數據頁,得到最新結果的過程稱為 merge。
- 除了訪問這個數據頁會觸發 merge 外,系統有后台線程會定期 merge。
- 在數據庫正常關閉(shutdown)的過程中,也會執行 merge 操作。
- 為什么需要 Change Buffer ?
- 顯然,如果能夠將更新操作先記錄在 change buffer,減少讀磁盤,語句的執行速度會得到明顯的提升。
- 而且,數據讀入內存是需要占用 buffer pool 的,所以這種方式還能夠避免占用內存,提高內存利用率。
- Change buffer 的使用場景?
- 因為 merge 的時候是真正進行數據更新的時刻,而 change buffer 的主要目的就是將記錄的變更動作緩存下來
- 所以在一個數據頁做 merge 之前,change buffer 記錄的變更越多(也就是這個頁面上要更新的次數越多),收益就越大。
- 因此,對於寫多讀少的業務來說,頁面在寫完以后馬上被訪問到的概率比較小,此時 change buffer 的使用效果最好。
- 這種業務模型常見的就是賬單類、日志類的系統。
- 反過來,假設一個業務的更新模式是寫入之后馬上會做查詢。
- 那么即使滿足了條件,將更新先記錄在 change buffer,但之后由於馬上要訪問這個數據頁,會立即觸發 merge 過程。
- 這樣隨機訪問 IO 的次數不會減少,反而增加了 change buffer 的維護代價。
- 所以,對於這種業務模式來說,change buffer 反而起到了副作用。
六:在看 唯一索引 和 普通索引的性能問題?
- 唯一索引
- 所有的更新操作都要先判斷這個操作是否違反唯一性約束。
- 比如,要插入 (4,400) 這個記錄,就要先判斷現在表中是否已經存在 k=4 的記錄,而這必須要將數據頁讀入內存才能判斷。
- 如果都已經讀入到內存了,那直接更新內存會更快,就沒必要使用 change buffer 了。
- 因此,唯一索引的更新就不能使用 change buffer,實際上也只有普通索引可以使用。
- 普通索引
- 正常使用 change buffer 更新。
- 結論
- 其實,這兩類索引在查詢能力上是沒差別的,主要考慮的是對更新性能的影響。
- 如果所有的更新后面,都馬上伴隨着對這個記錄的查詢,那么你應該關閉 change buffer。而在其他情況下,change buffer 都能提升更新性能。
- 在實際使用中,你會發現,普通索引和 change buffer 的配合使用,對於數據量大的表的更新優化還是很明顯的。
七:Redo log 和 Change Buffer
- 能力
- Redo log 用於寫入內存,完成更改,提供 cash-safe 的能力。
- Change Buffer 用於記錄更新內容,批量更新。
- 共同工作流程
- 更新數據
- 在內存中,直接更新內存;
- 沒有在內存中,就在內存的 change buffer 區域,記錄下“我要更改 xxx”這個信息
- 將上述兩個動作記入 redo log 中.
- 事務完成。
- 執行這條更新語句的成本很低,就是寫了兩處內存,然后寫了一處磁盤(兩次操作合在一起寫了一次磁盤),而且還是順序寫的。
-優勢
- Redo log 主要節省的是隨機寫磁盤的 IO 消耗(轉成順序寫),而 Change Buffer 主要節省的則是隨機讀磁盤的 IO 消耗。