1. 程式人生 > 其它 >普通索引和唯一索引的區別

普通索引和唯一索引的區別

查詢

唯一索引

這裡我們以下面的語句為例子進行介紹:這裡的card_id就是唯一索引

select * from t_user where card_id = 142733

當InnoDB引擎查詢到第一條符合條件的記錄時就會返回,因為唯一索引保證了欄位的唯一性;

普通索引

這裡我們以下面的語句為例子進行介紹:這裡的name就是普通索引,因為人名會有重複

select * from t_user where name = javalover

當InnoDB引擎查詢到第一條符合條件的記錄時,還會繼續往後查詢,直到不符合條件為止;

從表面上來看,好像普通索引的效能會低一些,因為它查的多啊

實際結果是:唯一索引和普通索引的查詢效能,差別並不大

因為mysql的資料操作並不是每查詢一條,就去磁碟中取一條,而是按頁去磁碟中取的;

按頁取的資料會存在記憶體中(change buffer下面會介紹),供後續的查詢和更新使用;

這樣一來,從記憶體中讀取連續的資料,對於伺服器來說,就沒啥壓力了,多讀幾個資料差別也就沒有多大了;


不過如果讀取的資料剛好在資料頁的末尾,那麼效能可能會稍微低一點; 不過這個概率比較低,因為一個數據頁的預設大小是16KB,大概可以儲存上千個整型數值;

更新

如果要更新的資料頁在記憶體中,那唯一索引和普通索引沒啥區別,都是找到對應的索引然後直接更新;

如果要更新的資料頁不在記憶體中,那更新過程兩者會稍有不同

唯一索引

需要先把資料頁從磁碟中讀取出來,然後再去找到對應的索引進行更新;

普通索引

不會從磁碟中讀取資料頁,而是直接把更新操作儲存在記憶體中(change buffer);

然後記憶體中的資料再在合適的時機,合併到資料庫磁碟中;

這樣來看的話,差距就很明顯了,普通索引的效能會更好一點;

因為唯一索引的每次更新都要去磁碟中讀取資料,這會涉及到磁碟的隨機IO操作,而磁碟的隨機IO操作,在資料庫裡面屬於成本比較高的操作之一了。

change buffer

定義:change buffer就是一塊記憶體區域,用來儲存更新操作

這裡我們需要注意一點,雖然change buffer聽起來像是一個快取區,應該只存在於記憶體中;但是實際上change buffer也是會持久化到磁碟中的;

上面我們提到了change buffer會在合適的時機,將它裡面的資料合併(merge)到資料庫磁碟中;

合併(merge)的過程是怎麼樣的呢?

合併就是把change buffer中的資料覆蓋到資料庫磁碟中舊的資料頁,使其變成一個新的資料頁的過程;

  1. 合併的第一步就是先把舊的資料頁從資料庫磁碟讀到記憶體中,然後根據change buffer中的更新操作去更新舊的資料頁;
  1. 此時會得到一個新的資料頁,也叫做髒頁,因為這個時候記憶體中的新資料頁和資料庫磁碟中的資料頁是不一樣的;
  2. 最後刷髒頁到磁碟中,就是把新的資料頁寫入到磁碟中,這個刷髒頁可能發生在系統記憶體不足時,也可能發生在系統空閒時等等(關於髒頁的細節可以參考網上的資源)

有多種情況,比如:

  1. 當change buffer中的更新操作 對應的資料頁有查詢操作時,就會執行merge合併,因為不合並的話,從磁碟中讀的資料頁是舊的資料,而change buffer中儲存的只是更新操作,無法直接讀取;
  2. 系統後臺定期merge合併;
  3. 資料庫正常關閉時,也會執行merge合併;

change buffer的好處體現在哪裡呢?

兩個方面:

  1. 提高語句的執行效率:因為有了change buffer,就不用每次更新都去磁碟中讀取資料頁,然後更新,只需要將更新操作儲存即可;
  2. 節省記憶體,提高記憶體的利用率:這個其實跟上面的原因是一樣的,因為不用去磁碟中讀取資料頁,那自然就不用在記憶體中(buffer pool)儲存那部分資料頁,這樣記憶體就可以省下來幹別的事情;(不過change buffer也是用的buffer pool的記憶體,只是佔的比資料頁要少)

上面我們提到了合併操作的時機,第一個就是在語句查詢時發生;

而合併操作是需要訪問資料庫的磁碟的,所以如果剛寫的資料沒多久就要查詢,而且很頻繁,那就不適合用change buffer了;

change buffer的使用場合

因為這個時候不僅磁碟的隨機IO訪問沒有減少,還增加了change buffer的維護成本,得不償失了;

所以change buffer的適用場合是寫多讀少的場合,比如日誌系統等;

總結

唯一索引就是欄位值唯一,不會重複,一般在業務無法保證資料的唯一性時,才考慮使用唯一索引;

普通索引的更新操作,會用到change buffer,此時系統會直接把更新操作儲存到change buffer中,然後返回,表現出來的效果就是更新很快;然後change buffer再在下次查詢時將資料merge到資料庫磁碟,或者系統後臺定期merge等等;