普通索引和惟一索引,應該怎麼選擇?

若是業務能保證惟一性的狀況下,仍是選擇普通索引性能更好mysql

select id from T where k=5sql

首先,咱們看下數據庫

查詢過程

對於普通索引來講,查詢到知足條件的第一個記錄後,須要查找下一個記錄,直到碰到第一個不知足k=5條件的記錄性能

對於惟一索引來講,因爲索引上有惟一性,查詢到第一個知足條件的記錄後就中止檢索了線程

因此在這裏的區別就是普通索引會多查那麼一下,那麼這兩種的性能差異有多大呢?指針

答案是微乎其微,爲甚呢?日誌

由於mysql在讀數據的時候,好比說上面那條語句,若是沒有在內存中,會去磁盤中把k=5這條數據所在的整個數據頁都讀入內存中,在innodb中,每一個數據頁的大小默認是16KB,由於引擎是按頁讀寫的,因此說,當找到k=5的記錄的時候,它所在的數據頁都在內存裏了,那麼對於普通索引來講,要多作的那一次查詢的操做,就只須要一次指針尋找和一次計算,固然,若是K=5這個記錄恰好是這個數據頁的最後一個記錄,那麼要取下一個記錄,必須讀取下一個數據頁,這個操做會稍微複雜一些,可是對於整形字段,一個數據頁能夠放近千個key,所以出現這種狀況的機率會很低,因此,咱們計算平均性能差別時,扔能夠認爲這個操做成本對於如今的cpu來講能夠忽略不計。索引

更新過程

首先咱們說下change_buffer的概念,若是要更新的數據在內存中,那麼就直接更新內存,若是要更新的數據沒有在內存中,那麼就會把更新記錄存在change_buffer中,等到有查詢來讀取數據頁的時候,就會執行change_buffe中有關這個數據頁的操做。經過這種方式就能保證這個數據邏輯的正確性。內存

change_buffer也會持久化到磁盤,將change_buffer中的操做應用到原數據頁,獲得最新結果的過程稱爲merge,除了訪問這個數據頁會觸發merge外,系統有後臺線程會按期merge,在數據庫正常關閉的過程當中,也會執行mergeio

顯然若是可以將更新操做記錄在change_buffer,減小讀磁盤,語句的執行速度會獲得明顯的提高。並且,數據讀入內存是須要佔用buffer pool的,因此這種方式還可以避免佔用內存,提升內存利用率

那麼什麼條件下可使用changebuffer呢?

對於惟一索引來講,每次更新都必須先判斷這個操做是否違反惟一性約束,好比,要插入(4,400)這個記錄,就要先判斷如今表中是否存在這個記錄,而這必需要將數據頁讀入內存才能判斷,既然都讀入內存了,那麼直接更新內存會更快,就不必使用change buffer了。

所以,惟一索引的更新就不能使用change buffer

change buffer用的是buffer pool裏的內存,由於不能無限增大,change buffer的大小,能夠經過參數innodb_change_buffer_max_size來動態設置,這個參數設置爲50的時候,表示change buffer的大小最多隻能佔用buffer pool的50%

如今咱們看下若是要在這張表中插入一個新記錄(4,400)的話,innodb的處理流程是什麼樣的

第一種狀況是,這個記錄要更新的目標頁在內存中,這時,innodb的處理流程以下:

  • 對於惟一索引來講,找到3和5之間的位置,判斷到沒有衝突,插入這個值,語句執行結束
  • 對於普通索引來講,找到3和5的位置,插入這個值,語句執行結束

這樣看來,普通索引和惟一索引對更新語句性能影響的差異,只是一個判斷,只會耗費微小的CPU時間。

但,這不是咱們關注的重點

第二中狀況是,這個記錄要更新的目標頁不在內存中,這時,流程以下:

  • 對於惟一索引來講,因爲須要判斷惟一性,因此要從磁盤中讀取所在的數據頁到內存中,判斷到沒有衝突,插入值,結束
  • 對於普通索引來講,則是將更新記錄在change buffer,結束

將數據從磁盤讀入內存涉及隨機io的訪問,是數據庫裏面成本最高的操做之一。changebuffer由於減小了隨機磁盤訪問,因此對更新性能的提高是會很明顯的

可是change buffer的應用場景只是對於寫多讀少的的業務,頁面在寫完之後立刻被訪問的機率比較小,此時changebuffer的使用效果最好,這種業務模型常見的就是帳單類,日誌類的系統。

反過來,若是一個業務的更新模式是寫完以後立刻會作查詢,那麼即便知足了條件,將更新記錄在change buffer,但以後因爲立刻要訪問這個數據頁,會當即觸發Merge過程,這樣隨機訪問io的次數不會減小,反而增長了change buffer的維護代價。因此,對於這種業務模式來講,change buffer反而起到了副作用。

因此,若是全部的更新後面,都立刻伴隨着對這個記錄的查詢,那麼你應該關閉change buffer,而在其餘狀況下,change buffer都能提高更新性能。

小結

若是業務能保證一個字段的惟一性而且針對的是寫多多少的業務模式,那麼仍是選擇普通索引的好。

相關文章
相關標籤/搜索