亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MySQL唯一索引和普通索引選哪個(gè)?

 更新時(shí)間:2020年10月13日 14:27:23   作者:以終為始  
這篇文章主要介紹了MySQL唯一索引和普通索引的優(yōu)劣,幫助大家更好的理解和使用MySQL索引,感興趣的朋友可以了解下

想象這樣一個(gè)場(chǎng)景,在設(shè)計(jì)一張用戶(hù)表時(shí),每人的身份證號(hào)是唯一的,需要搜索。但由于身份證號(hào)字段較大,不好將其作為主鍵。在業(yè)務(wù)代碼已經(jīng)保證插入身份證唯一的情況下,可以選擇建立唯一索引和普通索引,這時(shí)該如何選擇呢?接下來(lái),將從查詢(xún)和更新的執(zhí)行過(guò)程進(jìn)行分析。

查詢(xún)過(guò)程

假設(shè) k 是表 t 上的索引,在搜索 select id from t where k=5 時(shí),會(huì)先從 k 這棵 B+ 的樹(shù)根開(kāi)始,按層搜索葉子節(jié)點(diǎn),找到 k=5 的數(shù)據(jù)頁(yè),然后在數(shù)據(jù)頁(yè)內(nèi)容進(jìn)行二分法定位。

對(duì)于普通索引,找到 k=5 的記錄后,會(huì)繼續(xù)向下查找一個(gè),直到碰到第一個(gè)不是 5 的記錄結(jié)束。

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

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

如果 k=5 是當(dāng)前數(shù)據(jù)頁(yè)的最后一條,就需要在讀取下一個(gè)數(shù)據(jù)頁(yè)。但這發(fā)生的概率較低,也可以忽略。

所以總得來(lái)說(shuō),普通索引和唯一索引在查詢(xún)的過(guò)程中差異不大。

change buffer

在分析唯一索引和普通索引的影響前,先來(lái)認(rèn)識(shí)一下 change buffer 這個(gè)結(jié)構(gòu)。

什么是 change buffer ?

在執(zhí)行更新操作時(shí),如果要更新的數(shù)據(jù)頁(yè)在內(nèi)存中就直接更新,否則的話,在不影響數(shù)據(jù)一致性的前提下,InnoDB 會(huì)將更新操作緩存在 change buffer 中,從而省去了從磁盤(pán)讀取數(shù)據(jù)頁(yè)的過(guò)程。在下次查詢(xún)操作讀取到恰好需要更新的數(shù)據(jù)頁(yè)時(shí),會(huì)將 change buffer 的更新語(yǔ)句執(zhí)行,寫(xiě)入數(shù)據(jù)頁(yè)。將操作應(yīng)用到硬盤(pán)的過(guò)程叫 merge. 后臺(tái)線程會(huì)定期 merge 或 數(shù)據(jù)庫(kù)正常關(guān)閉時(shí),也會(huì)進(jìn)行 merge 操作。

merge 的執(zhí)行流程:

  1. 從磁盤(pán)讀入老版本數(shù)據(jù)頁(yè)。
  2. 從 change buffer中找出和該數(shù)據(jù)頁(yè)關(guān)聯(lián)的記錄,依次應(yīng)用,得到新版數(shù)據(jù)頁(yè)。
  3. 寫(xiě) redo log,記錄數(shù)據(jù)的變更和 change buffer 的變更。

change buffer 實(shí)際上是可以持久化到硬盤(pán)中的數(shù)據(jù),也就是說(shuō)在內(nèi)存和硬盤(pán)上都 change buffer 的存在。change buffer 之前叫 insert buffer,開(kāi)始只對(duì) insert buffer 有優(yōu)化,后來(lái)加上了對(duì) delete 和 update 的支持,進(jìn)而改名叫 change buffer。

可以看到,先將更新操作記錄在 change buffer,減少了將磁盤(pán)數(shù)據(jù)頁(yè)讀取到內(nèi)存的過(guò)程,語(yǔ)句的執(zhí)行速度會(huì)有很明顯的提升。同時(shí),將數(shù)據(jù)讀入內(nèi)存,會(huì)占用 buffer pool 內(nèi)存,所以減少讀操作,還提高了內(nèi)存使用率。

Buffer Pool 是內(nèi)存中的一個(gè)區(qū)域,InnoDB 在訪問(wèn)表和索引數(shù)據(jù)時(shí)會(huì)在其中進(jìn)行緩存。允許在內(nèi)存中直接更新經(jīng)常使用的數(shù)據(jù),來(lái)加快處理速度。在一些專(zhuān)用的服務(wù)器上,會(huì)將 80% 的物理內(nèi)存分為 buffer pool.

可以通過(guò) innodb_change_buffer_max_size 來(lái)設(shè)置 change buffer 占用 buffer pool 的大小。

change buffer 應(yīng)用場(chǎng)景?

如上面提到,change buffer 預(yù)先保存了更新記錄,減少了讀取數(shù)據(jù)頁(yè)的過(guò)程,從而提高性能。也就是說(shuō)如果 change buffer 中針對(duì)不同的數(shù)據(jù)頁(yè)如果包含的更新記錄越多,其實(shí)收益也就越大。

因此對(duì)于寫(xiě)多讀少的業(yè)務(wù)(更新完立即查詢(xún))change buffer 發(fā)揮的作用也就越大。如常見(jiàn)的賬單類(lèi),日志類(lèi)等系統(tǒng)。

如果業(yè)務(wù)是更新完立即查詢(xún),雖然可以將更新記錄放在 change buffer 中,但由于之后要馬上查詢(xún)數(shù)據(jù)頁(yè),所以會(huì)立即觸發(fā) merge 過(guò)程。這樣隨機(jī)訪問(wèn) IO 次數(shù)并不會(huì)減少,反而增加了 change buffer 的維護(hù)代價(jià),起到反效果。

更新過(guò)程

對(duì)于唯一索引來(lái)說(shuō),所有的更新操作都需要判斷是否違反唯一性約束。所以必須把所需要的數(shù)據(jù)頁(yè)讀入內(nèi)存,然后直接更新就可以,不需要使用 change buffer. 所以 change buffer 只對(duì)普通索引有用。

具體分析下,對(duì)于一張表插入一個(gè)新記錄:

如果新記錄要更新的數(shù)據(jù)頁(yè)在內(nèi)存中:

對(duì)于唯一索引,找到合適的位置,判斷有沒(méi)有沖突,插入值,語(yǔ)句結(jié)束。

對(duì)于普通索引:找到位置,插入值,語(yǔ)句結(jié)束。

所以數(shù)據(jù)頁(yè)在內(nèi)存時(shí),唯一和普通索引就差一個(gè)判斷的過(guò)程。可以忽略。

如果新記錄要更新的數(shù)據(jù)頁(yè)不在內(nèi)存中:

對(duì)于唯一索引,將數(shù)據(jù)頁(yè)讀入內(nèi)存,判斷沖突,插入,語(yǔ)句結(jié)束。

對(duì)于普通索引,將語(yǔ)句記錄在 change buffer 中,語(yǔ)句結(jié)束。

由于從磁盤(pán)到內(nèi)存涉及隨機(jī) IO 訪問(wèn),是數(shù)據(jù)庫(kù)成本最高的操作之一。普通索引比唯一索引減少的讀入操作,可以有很好的性能提升。

唯一或普通索引的選擇

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

主要的差異是在更新過(guò)程中,要更新的數(shù)據(jù)頁(yè)并不在內(nèi)容中的情況。這時(shí)唯一索引,由于需要唯一性檢查,不能利用 change buffer. 多了從磁盤(pán)到內(nèi)容讀取數(shù)據(jù)的過(guò)程,其中涉及隨機(jī) IO 的訪問(wèn),相對(duì)來(lái)說(shuō)效率就低了。

所以如果業(yè)務(wù)需要更新不錯(cuò)的性能,這時(shí)可以選用普通索引。當(dāng)然一切都是建立在能保證數(shù)據(jù)準(zhǔn)確性的前提下。

當(dāng)如果更新后來(lái)緊接著查詢(xún)操作,可以考慮關(guān)掉 change buffer. 其他的情況,change buffer 都能有很好的提升。

特別針對(duì)機(jī)械硬盤(pán),change buffer 效果很顯著。

redo log 和 change buffer 的比較

InnoDB 中 redo log 的出現(xiàn)使其具有了 crash-safe 的能力,同時(shí)還提高了效率,通過(guò) WAL 先寫(xiě)日志,再寫(xiě)磁盤(pán)。

而 change buffer 是節(jié)省了從磁盤(pán)讀入數(shù)據(jù)頁(yè)到內(nèi)存的隨機(jī)IO過(guò)程。

下面通過(guò)一條插入語(yǔ)句來(lái)分析下兩者間的關(guān)系:

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

假設(shè) k 為普通索引,k1 所插入的數(shù)據(jù)頁(yè)在內(nèi)存中, k2 不在。

執(zhí)行插入操作時(shí),主要涉及了圖中這四部分的內(nèi)容:

InnoDB buffer pool:內(nèi)存區(qū)域

redo log:日志

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

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

innodb_file_per_table 開(kāi)啟時(shí),表被創(chuàng)建在獨(dú)立的表空間下,否則的話被創(chuàng)建在系統(tǒng)的表空間下。

執(zhí)行過(guò)程如下:

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

可以看到這條更新語(yǔ)句(包括插入,刪除,更新操作)執(zhí)行成本很低,兩次寫(xiě)入內(nèi)存,1次順序?qū)懭氪疟P(pán)。虛線的操作,是后臺(tái)操作,不影響響應(yīng)時(shí)間。

再來(lái)看一條查詢(xún)語(yǔ)句:

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

假設(shè)讀語(yǔ)句發(fā)生在更新語(yǔ)句不久,內(nèi)存數(shù)據(jù)還在,此時(shí)讀操作就和系統(tǒng)表空間和 redo log 無(wú)關(guān)。

執(zhí)行過(guò)程:

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

總結(jié)下 redo log 和 change buffer 的關(guān)系:

存儲(chǔ)位置:change buffer 也會(huì)持久化在硬盤(pán)里,但保存在系統(tǒng)表空間 ibdata1 里。而 redo log 是單獨(dú)的文件。

記錄內(nèi)容:change buffer 記錄的是更新操作的內(nèi)容,而 redo log 記錄的是普通數(shù)據(jù)頁(yè)的修改和 change buffer 的改動(dòng)。

同步磁盤(pán)過(guò)程:同步內(nèi)存中數(shù)據(jù)頁(yè)的修改時(shí)通過(guò) merge 操作進(jìn)行的,而不是根據(jù) redo log.

從更新的過(guò)程來(lái)看: redo log 將隨機(jī)寫(xiě)磁盤(pán)的 IO 轉(zhuǎn)換成了順序?qū)?,?change buffer 則是節(jié)省了隨機(jī)讀磁盤(pán)的 IO 消耗。

如果服務(wù)器異常掉電,會(huì)不會(huì)導(dǎo)致 change buffer 丟失?

并不會(huì),因?yàn)?change buffer 中的數(shù)據(jù)已經(jīng)被記錄到 redo log 中,所以不會(huì)丟失。

由于 change buffer 一部分?jǐn)?shù)據(jù)在磁盤(pán),一部分在內(nèi)存。對(duì)于在磁盤(pán)的數(shù)據(jù)已經(jīng) merge 所以不會(huì)丟失。
對(duì)于在內(nèi)存中的數(shù)據(jù):

  1. 如果 change buffer 寫(xiě)入,但 redo log 未提交,binlog 未提交,事務(wù)會(huì)回滾,這部分?jǐn)?shù)據(jù)不存在。
  2. 如果 change buffer 寫(xiě)入,redo log 寫(xiě)入,binlog 寫(xiě)入,并已提交,不會(huì)丟失。從 redo log 直接恢復(fù)。
  3. 如果 change buffer 寫(xiě)入,redo log 寫(xiě)入但未 commit,binlog 寫(xiě)入,從 binlog 恢復(fù) redo log 再恢復(fù) change buffer.

參考資料

Buffer Pool

以上就是MySQL唯一索引和普通索引選哪個(gè)?的詳細(xì)內(nèi)容,更多關(guān)于MySQL唯一索引和普通索引的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • mysql去重的兩種方法詳解及實(shí)例代碼

    mysql去重的兩種方法詳解及實(shí)例代碼

    這篇文章主要介紹了mysql去重的兩種方法詳解及實(shí)例代碼的相關(guān)資料,這里對(duì)去重的兩種方法進(jìn)行了一一實(shí)例詳解,需要的朋友可以參考下
    2017-01-01
  • 總結(jié)MySQL建表、查詢(xún)優(yōu)化的一些實(shí)用小技巧

    總結(jié)MySQL建表、查詢(xún)優(yōu)化的一些實(shí)用小技巧

    本篇文章是對(duì)MySQL建表以及查詢(xún)優(yōu)化的一些實(shí)用小技巧進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-07-07
  • mysql中格式化日期詳解

    mysql中格式化日期詳解

    最近因?yàn)楣ぷ餍枰褂胢ysql查詢(xún)記錄可如果有時(shí)間戳字段時(shí),查看結(jié)果不方便,不能即時(shí)看到時(shí)間戳代表的含義,所以這篇文章就提供mysql格式換時(shí)間函數(shù),可以方便的看到格式化后的時(shí)間。有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。
    2016-11-11
  • Mysql join連接查詢(xún)的語(yǔ)法與示例

    Mysql join連接查詢(xún)的語(yǔ)法與示例

    這篇文章主要給大家介紹了關(guān)于Mysql join連接查詢(xún)的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Mysql分析設(shè)計(jì)表主鍵為何不用uuid

    Mysql分析設(shè)計(jì)表主鍵為何不用uuid

    在mysql中設(shè)計(jì)表的時(shí)候,mysql官方推薦不要使用uuid或者不連續(xù)不重復(fù)的雪花id(long形且唯一),而是推薦連續(xù)自增的主鍵id,官方的推薦是auto_increment,那么為什么不建議采用uuid,使用uuid究竟有什么壞處?本篇博客我們就來(lái)分析這個(gè)問(wèn)題,探討一下內(nèi)部的原因
    2022-03-03
  • mysql 5.7.21 winx64綠色版安裝配置方法圖文教程

    mysql 5.7.21 winx64綠色版安裝配置方法圖文教程

    這篇文章主要為大家詳細(xì)介紹了mysql 5.7.21 winx64綠色版安裝配置方法圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • MySQL數(shù)據(jù)庫(kù)備份以及常用備份工具集合

    MySQL數(shù)據(jù)庫(kù)備份以及常用備份工具集合

    數(shù)據(jù)庫(kù)備份種類(lèi)按照數(shù)據(jù)庫(kù)大小備份,有四種類(lèi)型,分別應(yīng)用于不同場(chǎng)合。本文將MySQL 數(shù)據(jù)庫(kù)備份種類(lèi)以及常用備份工具進(jìn)行匯總,方便大家學(xué)習(xí)。
    2015-08-08
  • MYSQL中 TYPE=MyISAM 錯(cuò)誤的解決方法

    MYSQL中 TYPE=MyISAM 錯(cuò)誤的解決方法

    這篇文章主要介紹了MYSQL中 TYPE=MyISAM 錯(cuò)誤的解決方法,需要的朋友可以參考下
    2014-08-08
  • mysql數(shù)據(jù)庫(kù)修改數(shù)據(jù)表引擎的方法

    mysql數(shù)據(jù)庫(kù)修改數(shù)據(jù)表引擎的方法

    對(duì)于MySQL數(shù)據(jù)庫(kù),如果你要使用事務(wù)以及行級(jí)鎖就必須使用INNODB引擎。如果你要使用全文索引,那必須使用myisam,那如何修改修改MySQL的引擎為INNODB呢,下面介紹一個(gè)修改方法
    2014-01-01
  • Mysql動(dòng)態(tài)更新數(shù)據(jù)庫(kù)腳本的示例講解

    Mysql動(dòng)態(tài)更新數(shù)據(jù)庫(kù)腳本的示例講解

    今天小編就為大家分享一篇關(guān)于Mysql動(dòng)態(tài)更新數(shù)據(jù)庫(kù)腳本的示例講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12

最新評(píng)論