91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MySQL中唯一索引和普通索引哪個好

發布時間:2020-10-28 16:35:44 來源:億速云 閱讀:474 作者:Leah 欄目:開發技術

今天就跟大家聊聊有關MySQL中唯一索引和普通索引哪個好,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

想象這樣一個場景,在設計一張用戶表時,每人的身份證號是唯一的,需要搜索。但由于身份證號字段較大,不好將其作為主鍵。在業務代碼已經保證插入身份證唯一的情況下,可以選擇建立唯一索引和普通索引,這時該如何選擇呢?接下來,將從查詢和更新的執行過程進行分析。

查詢過程

假設 k 是表 t 上的索引,在搜索 select id from t where k=5 時,會先從 k 這棵 B+ 的樹根開始,按層搜索葉子節點,找到 k=5 的數據頁,然后在數據頁內容進行二分法定位。

對于普通索引,找到 k=5 的記錄后,會繼續向下查找一個,直到碰到第一個不是 5 的記錄結束。

對于唯一索引,由于取值唯一,找到后直接停止。

由于 InnoDB 是按照數據頁為單位(數據頁默認 16 KB)進行讀寫的,在讀取一條數據時,會將整個數據頁整體讀到內存。 在讀入內存的數據頁中,如果包含 k=5 的記錄,在查詢的情況下,唯一索引比普通索引多了一次查找和判斷的過程,可以忽略。

如果 k=5 是當前數據頁的最后一條,就需要在讀取下一個數據頁。但這發生的概率較低,也可以忽略。

所以總得來說,普通索引和唯一索引在查詢的過程中差異不大。

change buffer

在分析唯一索引和普通索引的影響前,先來認識一下 change buffer 這個結構。

什么是 change buffer ?

在執行更新操作時,如果要更新的數據頁在內存中就直接更新,否則的話,在不影響數據一致性的前提下,InnoDB 會將更新操作緩存在 change buffer 中,從而省去了從磁盤讀取數據頁的過程。在下次查詢操作讀取到恰好需要更新的數據頁時,會將 change buffer 的更新語句執行,寫入數據頁。將操作應用到硬盤的過程叫 merge. 后臺線程會定期 merge 或 數據庫正常關閉時,也會進行 merge 操作。

merge 的執行流程:

  1. 從磁盤讀入老版本數據頁。
  2. 從 change buffer中找出和該數據頁關聯的記錄,依次應用,得到新版數據頁。
  3. 寫 redo log,記錄數據的變更和 change buffer 的變更。

change buffer 實際上是可以持久化到硬盤中的數據,也就是說在內存和硬盤上都 change buffer 的存在。change buffer 之前叫 insert buffer,開始只對 insert buffer 有優化,后來加上了對 delete 和 update 的支持,進而改名叫 change buffer。

可以看到,先將更新操作記錄在 change buffer,減少了將磁盤數據頁讀取到內存的過程,語句的執行速度會有很明顯的提升。同時,將數據讀入內存,會占用 buffer pool 內存,所以減少讀操作,還提高了內存使用率。

Buffer Pool 是內存中的一個區域,InnoDB 在訪問表和索引數據時會在其中進行緩存。允許在內存中直接更新經常使用的數據,來加快處理速度。在一些專用的服務器上,會將 80% 的物理內存分為 buffer pool.

可以通過 innodb_change_buffer_max_size 來設置 change buffer 占用 buffer pool 的大小。

change buffer 應用場景?

如上面提到,change buffer 預先保存了更新記錄,減少了讀取數據頁的過程,從而提高性能。也就是說如果 change buffer 中針對不同的數據頁如果包含的更新記錄越多,其實收益也就越大。

因此對于寫多讀少的業務(更新完立即查詢)change buffer 發揮的作用也就越大。如常見的賬單類,日志類等系統。

如果業務是更新完立即查詢,雖然可以將更新記錄放在 change buffer 中,但由于之后要馬上查詢數據頁,所以會立即觸發 merge 過程。這樣隨機訪問 IO 次數并不會減少,反而增加了 change buffer 的維護代價,起到反效果。

更新過程

對于唯一索引來說,所有的更新操作都需要判斷是否違反唯一性約束。所以必須把所需要的數據頁讀入內存,然后直接更新就可以,不需要使用 change buffer. 所以 change buffer 只對普通索引有用。

具體分析下,對于一張表插入一個新記錄:

如果新記錄要更新的數據頁在內存中:

對于唯一索引,找到合適的位置,判斷有沒有沖突,插入值,語句結束。

對于普通索引:找到位置,插入值,語句結束。

所以數據頁在內存時,唯一和普通索引就差一個判斷的過程。可以忽略。

如果新記錄要更新的數據頁不在內存中:

對于唯一索引,將數據頁讀入內存,判斷沖突,插入,語句結束。

對于普通索引,將語句記錄在 change buffer 中,語句結束。

由于從磁盤到內存涉及隨機 IO 訪問,是數據庫成本最高的操作之一。普通索引比唯一索引減少的讀入操作,可以有很好的性能提升。

唯一或普通索引的選擇

通過在查詢和更新方面,兩者的比較。我們知道,在查詢過程中,除了極特殊情況,其實兩者的差異并不大。

主要的差異是在更新過程中,要更新的數據頁并不在內容中的情況。這時唯一索引,由于需要唯一性檢查,不能利用 change buffer. 多了從磁盤到內容讀取數據的過程,其中涉及隨機 IO 的訪問,相對來說效率就低了。

所以如果業務需要更新不錯的性能,這時可以選用普通索引。當然一切都是建立在能保證數據準確性的前提下。

當如果更新后來緊接著查詢操作,可以考慮關掉 change buffer. 其他的情況,change buffer 都能有很好的提升。

特別針對機械硬盤,change buffer 效果很顯著。

redo log 和 change buffer 的比較

InnoDB 中 redo log 的出現使其具有了 crash-safe 的能力,同時還提高了效率,通過 WAL 先寫日志,再寫磁盤。

而 change buffer 是節省了從磁盤讀入數據頁到內存的隨機IO過程。

下面通過一條插入語句來分析下兩者間的關系:

mysql> insert into t(id,k) values(id1,k1),(id2,k2);

假設 k 為普通索引,k1 所插入的數據頁在內存中, k2 不在。

MySQL中唯一索引和普通索引哪個好

執行插入操作時,主要涉及了圖中這四部分的內容:

InnoDB buffer pool:內存區域

redo log:日志

system table space(ibdata1):系統表空間

data(t.idb): 數據表空間

innodb_file_per_table 開啟時,表被創建在獨立的表空間下,否則的話被創建在系統的表空間下。

執行過程如下:

  1. k1 所在的 page1 在內存中,直接更新內存
  2. k2 所在的 page2 不在內存中,記錄在 change buffer.
  3. 將 k1 和 k2 的操作記錄在 redo log.
  4. 提交事務。
     

可以看到這條更新語句(包括插入,刪除,更新操作)執行成本很低,兩次寫入內存,1次順序寫入磁盤。虛線的操作,是后臺操作,不影響響應時間。

再來看一條查詢語句:

select * from t where k in (k1, k2)

假設讀語句發生在更新語句不久,內存數據還在,此時讀操作就和系統表空間和 redo log 無關。

MySQL中唯一索引和普通索引哪個好

執行過程:

  1. 讀取 k1 所在的 page1,在內存中,直接返回。注意,并沒有讀磁盤上的數據,而且磁盤上的數據還有可能是之前的版本的。
  2. 讀取 k2 所在的 page2,這時需要將 page2 從磁盤加載到內存,并應用 change buffer 的內容,然后返回正確的結果。從這里也能看出,change buffer 不適用于更新完立馬去讀的情況。
     

總結下 redo log 和 change buffer 的關系:

存儲位置:change buffer 也會持久化在硬盤里,但保存在系統表空間 ibdata1 里。而 redo log 是單獨的文件。

記錄內容:change buffer 記錄的是更新操作的內容,而 redo log 記錄的是普通數據頁的修改和 change buffer 的改動。

同步磁盤過程:同步內存中數據頁的修改時通過 merge 操作進行的,而不是根據 redo log.

從更新的過程來看: redo log 將隨機寫磁盤的 IO 轉換成了順序寫,而 change buffer 則是節省了隨機讀磁盤的 IO 消耗。

如果服務器異常掉電,會不會導致 change buffer 丟失?

并不會,因為 change buffer 中的數據已經被記錄到 redo log 中,所以不會丟失。

由于 change buffer 一部分數據在磁盤,一部分在內存。對于在磁盤的數據已經 merge 所以不會丟失。
對于在內存中的數據:

  1. 如果 change buffer 寫入,但 redo log 未提交,binlog 未提交,事務會回滾,這部分數據不存在。
  2. 如果 change buffer 寫入,redo log 寫入,binlog 寫入,并已提交,不會丟失。從 redo log 直接恢復。
  3. 如果 change buffer 寫入,redo log 寫入但未 commit,binlog 寫入,從 binlog 恢復 redo log 再恢復 change buffer.

看完上述內容,你們對MySQL中唯一索引和普通索引哪個好有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

密云县| 泰兴市| 尚志市| 东阿县| 专栏| 嫩江县| 漯河市| 绍兴市| 蓬莱市| 宣城市| 磐安县| 巧家县| 潮安县| 马鞍山市| 鄂托克旗| 乌恰县| 叶城县| 沁阳市| 桃园县| 怀远县| 于田县| 锦州市| 安阳市| 南木林县| 齐齐哈尔市| 凤冈县| 库尔勒市| 甘孜| 司法| 密云县| 怀安县| 同仁县| 星座| 永德县| 保山市| 巴中市| 临沂市| 陆川县| 信丰县| 屏东县| 胶南市|