自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL性能優(yōu)化之Innodb事務(wù)系統(tǒng),值得收藏

數(shù)據(jù)庫 MySQL
在Innodb中,每次開啟一個(gè)事務(wù)時(shí),都會(huì)為該session分配一個(gè)事務(wù)對象。今天主要分享下Innodb事務(wù)系統(tǒng)的一些優(yōu)化相關(guān),以下基于mysql 5.7。

今天主要分享下Innodb事務(wù)系統(tǒng)的一些優(yōu)化相關(guān),以下基于mysql 5.7。

一、Innodb中的事務(wù)、視圖、多版本

1. 事務(wù)

在Innodb中,每次開啟一個(gè)事務(wù)時(shí),都會(huì)為該session分配一個(gè)事務(wù)對象。而為了對全局所有的事務(wù)進(jìn)行控制和協(xié)調(diào),有一個(gè)全局對象trx_sys,對trx_sys相關(guān)成員的操作需要trx_sys->mutex鎖。

mysql數(shù)據(jù)庫遵循的是兩段鎖協(xié)議,將事務(wù)分成兩個(gè)階段,加鎖階段和解鎖階段(所以叫兩段鎖)

  • 加鎖階段:在該階段可以進(jìn)行加鎖操作。在對任何數(shù)據(jù)進(jìn)行讀操作之前要申請并獲得S鎖(共享鎖,其它事務(wù)可以繼續(xù)加共享鎖,但不能加排它鎖),在進(jìn)行寫操作之前要申請并獲得X鎖(排它鎖,其它事務(wù)不能再獲得任何鎖)。加鎖不成功,則事務(wù)進(jìn)入等待狀態(tài),直到加鎖成功才繼續(xù)執(zhí)行。
  • 解鎖階段:當(dāng)事務(wù)釋放了一個(gè)封鎖以后,事務(wù)進(jìn)入解鎖階段,在該階段只能進(jìn)行解鎖操作不能再進(jìn)行加鎖操作。

MySQL性能優(yōu)化之Innodb事務(wù)系統(tǒng),值得收藏

2. 視圖

Innodb使用一種稱做ReadView(視圖)的對象來判斷事務(wù)的可見性(也就是ACID中的隔離性)。根據(jù)可見性原則,某個(gè)新開啟的事務(wù)不應(yīng)該看到其他未提交的事務(wù)。 Innodb在執(zhí)行一個(gè)SELECT或者顯式開啟START TRANSACTION WITH CONSISTENT SNAPSHOT (后者只應(yīng)用于REPEATABLE-READ隔離級別) 會(huì)創(chuàng)建一個(gè)視圖對象。對于RR隔離級別,視圖的生命周期到事務(wù)提交結(jié)束,對于RC隔離級別,則每條查詢開始時(shí)重分配事務(wù)。

MySQL性能優(yōu)化之Innodb事務(wù)系統(tǒng),值得收藏

通常一個(gè)視圖中包含創(chuàng)建視圖的事務(wù)ID,以及在創(chuàng)建視圖時(shí)活躍的事務(wù)ID數(shù)組。例如,當(dāng)開啟一個(gè)視圖時(shí),當(dāng)前事務(wù)的事務(wù)ID為5, 事務(wù)鏈表上活躍事務(wù)ID為{2,5,6,9,12},那么就會(huì)把{2,6,9,12}存儲(chǔ)到當(dāng)前的視圖中(5是當(dāng)前事務(wù)的ID,不記錄到視圖中),{2,6,9,12}對應(yīng)的事務(wù)所做的修改對當(dāng)前事務(wù)而言都是不可見的,小于2的事務(wù)ID對當(dāng)前事務(wù)都是可見的,大于12的事務(wù)ID對當(dāng)前事務(wù)是不可見的。

那么如何判斷可見性呢?

InnoDB表數(shù)據(jù)的組織方式為主鍵聚簇索引。由于采用索引組織表結(jié)構(gòu),記錄的ROWID是可變的(索引頁分裂的時(shí)候,Structure Modification Operation,SMO),因此二級索引中采用的是(索引鍵值, 主鍵鍵值)的組合來唯一確定一條記錄。無論是聚簇索引,還是二級索引,其每條記錄都包含了一個(gè)DELETED BIT位,用于標(biāo)識(shí)該記錄是否是刪除記錄。除此之外,聚簇索引記錄還有兩個(gè)系統(tǒng)列:DATA_TRX_ID,DATA_ROLL_PTR。DATA _TRX_ID表示產(chǎn)生當(dāng)前記錄項(xiàng)的事務(wù)ID;DATA _ROLL_PTR指向當(dāng)前記錄項(xiàng)的undo信息。

聚簇索引行結(jié)構(gòu)(與多版本一致讀有關(guān)的部分,DELETED BIT省略):

MySQL性能優(yōu)化之Innodb事務(wù)系統(tǒng),值得收藏

二級索引行結(jié)構(gòu):

MySQL性能優(yōu)化之Innodb事務(wù)系統(tǒng),值得收藏

從聚簇索引行結(jié)構(gòu),與二級索引行結(jié)構(gòu)可以看出,聚簇索引中包含版本信息(事務(wù)號(hào)+回滾指針),二級索引不包含版本信息。

對于聚集索引,每次修改記錄時(shí),都會(huì)在記錄中保存當(dāng)前的事務(wù)ID,同時(shí)舊版本記錄存儲(chǔ)在UNDO中;對于二級索引,則在二級索引頁中存儲(chǔ)了更新當(dāng)前頁的最大事務(wù)ID,如果該事務(wù)ID大于readview->up_limit_id(對于上例,up_limit_id值為2),那么就需要回聚集索引判斷記錄可見性;如果小于2, 那么總是可見的,可以直接讀取。

3. 多版本(MVCC)

為了便于理解MVCC的實(shí)現(xiàn)原理,這里簡單介紹一下undo log的工作過程

在不考慮redo log 的情況下利用undo log工作的簡化過程為:

MySQL性能優(yōu)化之Innodb事務(wù)系統(tǒng),值得收藏

說明:

  • 為了保證數(shù)據(jù)的持久性數(shù)據(jù)要在事務(wù)提交之前持久化
  • undo log的持久化必須在在數(shù)據(jù)持久化之前,這樣才能保證系統(tǒng)崩潰時(shí),可以用undo log來回滾事務(wù)

MVCC只在READ COMMITED 和 REPEATABLE READ 兩個(gè)隔離級別下工作。READ UNCOMMITTED總是讀取最新的數(shù)據(jù)行,而不是符合當(dāng)前事務(wù)版本的數(shù)據(jù)行。而SERIALIZABLE 則會(huì)對所有讀取的行都加鎖。

MySQL性能優(yōu)化之Innodb事務(wù)系統(tǒng),值得收藏

(1) SELECT

InnoDB 會(huì)根據(jù)兩個(gè)條件來檢查每行記錄:

  • InnoDB只查找版本(DB_TRX_ID)早于當(dāng)前事務(wù)版本的數(shù)據(jù)行(行的系統(tǒng)版本號(hào)<=事務(wù)的系統(tǒng)版本號(hào),這樣可以確保數(shù)據(jù)行要么是在開始之前已經(jīng)存在了,要么是事務(wù)自身插入或修改過的)
  • 行的刪除版本號(hào)(DB_ROLL_PTR)要么未定義(未更新過),要么大于當(dāng)前事務(wù)版本號(hào)(在當(dāng)前事務(wù)開始之后更新的)。這樣可以確保事務(wù)讀取到的行,在事務(wù)開始之前未被刪除。

(2) INSERT

InnoDB為新插入的每一行保存當(dāng)前系統(tǒng)版本號(hào)作為行版本號(hào)

(3) DELETE

InnoDB為刪除的每一行保存當(dāng)前的系統(tǒng)版本號(hào)作為行刪除標(biāo)識(shí)

(4) UPDATE

InnoDB為插入一行新記錄,保存當(dāng)前系統(tǒng)版本號(hào)作為行版本號(hào),同時(shí)保存當(dāng)前系統(tǒng)版本號(hào)到原來的行作為行刪除標(biāo)識(shí)。

Innodb的多版本數(shù)據(jù)使用UNDO來維護(hù)的,例如聚集索引記錄(1) =>(2)=>(3),從1更新成2,再更新成3,就會(huì)產(chǎn)生兩條undo記錄。

二、Innodb事務(wù)系統(tǒng)優(yōu)化

在MySQL 5.7版本里,針對性的對事務(wù)系統(tǒng)做了比較深入的優(yōu)化,主要解決了下面幾個(gè)問題。

1. 視圖對象的創(chuàng)建需要trx_sys->mutex鎖保護(hù)

trx_sys->mutex是事務(wù)系統(tǒng)最核心的全局鎖對象,持有該鎖進(jìn)行的操作都不應(yīng)該耗時(shí)過長。對于read view對象,完全可以將其緩存下來重復(fù)使用。這樣就避免了持有鎖分配視圖內(nèi)存。

因此在MySQL 5.7版本中,實(shí)例啟動(dòng)時(shí)就分配1024個(gè)視圖對象;同時(shí)維護(hù)兩個(gè)鏈表,一個(gè)是已使用的視圖鏈表,一個(gè)是空閑的視圖鏈表;當(dāng)需要分配新的視圖時(shí),總是從空閑視圖鏈表中分配,如果沒有,再新分配一個(gè)。

2. 視圖對象中保存全局事務(wù)ID時(shí),需要掃描事務(wù)鏈表

為了判斷事務(wù)視圖的可見性,在打開一個(gè)視圖時(shí)需要拷貝當(dāng)時(shí)活躍的事務(wù)ID。

在5.7中,事務(wù)系統(tǒng)維持了一個(gè)全局事務(wù)ID數(shù)組,每個(gè)活躍讀寫事務(wù)的ID都被加入到其中,在事務(wù)提交時(shí)從其中刪除,這樣打開視圖時(shí)只需要使用memcpy 拷貝該數(shù)組即可,無需遍歷鏈表。在讀寫鏈表較長(高并發(fā)下)的場景,該優(yōu)化可以顯著的提升性能。

3. 用戶需要顯式開啟只讀事務(wù),才會(huì)放入只讀事務(wù)鏈表

mysql5.7將只讀事務(wù)鏈表從其中徹底移除了,取而代之的是,所有事務(wù)都以只讀模式打開。

例如如下事務(wù)序列:

  1. BEGIN; 
  2. SELECT; //事務(wù)開始,不分配事務(wù)ID,不分配回滾段; 
  3. UPDATE; //分配事務(wù)ID并插入全局事務(wù)數(shù)組和事務(wù)對象集合中,分配回滾段; 
  4. COMMIT; 

而對于BEGIN;SELECT;SELECT;COMMIT這樣的序列,整個(gè)事務(wù)周期既不分配事務(wù)ID,也不分配回滾段。

4. 隱式鎖轉(zhuǎn)換為顯式鎖的開銷

Innodb對于類似INSERT操作,采用的是隱式鎖的方式,隱式鎖不是鎖,只是一種稱呼而已,只有在需要的時(shí)候,才會(huì)轉(zhuǎn)換為顯式鎖。例如如下:

  1. Session 1: BEING; INSERT INTO t1(pk, val) VALUES (1,2); //不創(chuàng)建鎖對象 
  2. Session 2: UPDATE t1 SET valval=val+1 WHERE pk=1; //創(chuàng)建兩個(gè)鎖對象,一個(gè)是為session1創(chuàng)建一個(gè)記錄鎖對象,另外一個(gè)是給自己創(chuàng)建一個(gè)等待類型的記錄鎖對象,然后session2加入鎖等待隊(duì)列。 

在Session 2中為Session1創(chuàng)建鎖對象的過程即是所謂的隱式鎖向顯式鎖轉(zhuǎn)換。 當(dāng)session2掃描到session 1插入的記錄時(shí),發(fā)現(xiàn)session 1的事務(wù)依然活躍,就會(huì)進(jìn)入轉(zhuǎn)換邏輯。

在5.6版本中,其轉(zhuǎn)換過程如下:

  • 持有l(wèi)ock_sys->mutex
  • 2持有trx_sys->mutex;根據(jù)事務(wù)ID,掃描讀寫事務(wù)鏈表,找到對應(yīng)的事務(wù)對象;釋放trx_sys->mutex;
  • 創(chuàng)建顯式鎖對象
  • 釋放lock_sys->mutex

可以看到,在該操作的過程中,全程持有l(wèi)ock_sys->mutex,持有鎖的原因是防止事務(wù)提交掉。當(dāng)讀寫事務(wù)鏈表非常長時(shí)(例如高并發(fā)寫入時(shí)),這種開銷將是不可接受的。

在5.7版本中,上述邏輯則優(yōu)化成:

(1)  持有trx_sys->mutex

  • 根據(jù)事務(wù)ID找到對應(yīng)的事務(wù)對象(直接查找trx_sys->rw_trx_set,其保存了trx_id和事務(wù)對象的映射關(guān)系,因此無需掃描讀寫事務(wù)鏈表)
  • 增加事務(wù)對象引用計(jì)數(shù)(++trx->n_ref)
  • 釋放trx_sys->mutex

(2) 持有l(wèi)ock_sys->mutex;

  • 創(chuàng)建顯式鎖對象;
  • 釋放lock_sys->mutex;

(3) 遞減事務(wù)對象引用計(jì)數(shù)

在事務(wù)commit,釋放記錄鎖前,會(huì)先判斷引用記錄數(shù)是否為0,如果不為0,表示正有其他事務(wù)為其轉(zhuǎn)換顯式鎖,這時(shí)候需要等待,直到計(jì)數(shù)為0,才能進(jìn)入釋放事務(wù)記錄鎖階段。

總的來說,該優(yōu)化減少了隱式鎖轉(zhuǎn)換時(shí)持有LOCK_sys->mutex的時(shí)間,從而提升性能。

責(zé)任編輯:趙寧寧 來源: 今日頭條
相關(guān)推薦

2023-11-15 16:35:31

SQL數(shù)據(jù)庫

2020-03-27 15:40:10

MySQL索引數(shù)據(jù)庫

2019-02-26 09:14:02

SSD狀態(tài)監(jiān)控

2011-06-14 14:17:23

性能優(yōu)化系統(tǒng)層次

2019-02-26 15:17:15

工具性能數(shù)據(jù)

2019-12-02 08:58:09

SQL腳本語言MySQL

2019-08-05 09:19:45

PG事務(wù)隔離級別數(shù)據(jù)庫

2019-07-29 17:15:35

MySQL操作系統(tǒng)數(shù)據(jù)庫

2019-09-26 08:59:39

DockerGoogle軟件

2019-10-22 18:00:00

MySQL基礎(chǔ)入門數(shù)據(jù)庫

2022-02-08 18:53:12

SpringBoot性能優(yōu)化

2011-03-11 15:53:02

LAMP優(yōu)化

2015-11-10 16:55:00

性能IO子系統(tǒng)Linux

2021-07-29 14:20:34

網(wǎng)絡(luò)優(yōu)化移動(dòng)互聯(lián)網(wǎng)數(shù)據(jù)存儲(chǔ)

2022-02-16 14:10:51

服務(wù)器性能優(yōu)化Linux

2018-06-01 16:24:29

數(shù)據(jù)庫MySQL Innod阻塞事務(wù)

2020-05-27 11:55:47

Oracle SQL性能優(yōu)化數(shù)據(jù)庫

2021-11-29 11:13:45

服務(wù)器網(wǎng)絡(luò)性能

2024-01-18 09:43:11

MySQL數(shù)據(jù)庫

2009-06-30 11:23:02

性能優(yōu)化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)