本篇文章給大家?guī)砹岁P(guān)于mysql的相關(guān)知識(shí),其中主要整理了rollback的相關(guān)問題,主要介紹了書屋回滾以及回滾機(jī)制等內(nèi)容,下面一起來看一下,希望對(duì)大家有幫助。
推薦學(xué)習(xí):mysql視頻教程
經(jīng)常會(huì)遇到操作一張大表,發(fā)現(xiàn)操作時(shí)間過長(zhǎng)或影響在線業(yè)務(wù),想要回退大表操作的場(chǎng)景。在停止大表操作之后,等待回滾是一個(gè)很漫長(zhǎng)的過程,盡管可能對(duì)知道一些縮短時(shí)間的方法,處于對(duì)生產(chǎn)環(huán)境數(shù)據(jù)完整性的敬畏,也會(huì)選擇不做介入。
事務(wù)回滾
事務(wù)是關(guān)系型數(shù)據(jù)庫(kù)里的執(zhí)行單位,可以通過最后階段控制選擇提交或回滾。在各種無法保證完整性的場(chǎng)景下進(jìn)行回滾操作。MySQL里回滾是通過Undo日志完成,Undo日志記錄包含關(guān)于如何撤消事務(wù)相關(guān)的最新更改的信息。Undo日志存在于Undo日志段中,Undo日志段包含在回滾段中。回滾段位于undo表空間和全局Temporary表空間中。
關(guān)系如下:
- undo文件
mysql > show variables like '%undo%'; +--------------------------+--------------------+ | Variable_name | Value | +--------------------------+--------------------+ | innodb_max_undo_log_size | 1073741824 | | innodb_undo_directory | /opt/data8.0/mysql | | innodb_undo_log_encrypt | OFF | | innodb_undo_log_truncate | ON | | innodb_undo_tablespaces | 2 | +--------------------------+--------------------+ 5 rows in set (0.00 sec)
全局Temporary所指的一個(gè)臨時(shí)表空間(ibtmp1),用于存儲(chǔ)對(duì)用戶創(chuàng)建的臨時(shí)表所做更改的回滾段。
mysql > SELECT @@innodb_temp_data_file_path; +-------------------------------+ | @@innodb_temp_data_file_path | +-------------------------------+ | ibtmp1:128M:autoextend:max:30G | +-------------------------------+
理解了回滾包含的文件都有那些 ,繼續(xù)往下看。
回滾機(jī)制:
MySQL回滾控制是內(nèi)部innodb引擎協(xié)調(diào)解決,不提供人為控制的機(jī)制。目前提供的MySQL回滾參數(shù)如下:
mysql> SHOW VARIABLES LIKE '%ROLL%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | innodb_rollback_on_timeout | OFF | | innodb_rollback_segments | 128 | +----------------------------+-------+
innodb_rollback_on_timeout:
InnoDB默認(rèn)只在事務(wù)超時(shí)時(shí)回滾最后一條語句。如果指定了——InnoDB -rollback-on-timeout,事務(wù)超時(shí)將導(dǎo)致InnoDB中止并回滾整個(gè)事務(wù)。默認(rèn)下是關(guān)閉的,一旦指定時(shí)間,如回滾失敗??梢韵胂蟮綌?shù)據(jù)會(huì)存在不一致的問題。這個(gè)方式不可取。
Innodb_rollback_segments(1~128):
定義了分配給每個(gè)undo表空間的回滾段的數(shù)量,以及為生成undo記錄的事務(wù)分配的全局臨時(shí)表空間的數(shù)量。
回滾段支持的事務(wù)數(shù)量:取決于回滾段中的撤銷slot數(shù)量以及每個(gè)事務(wù)所需的撤銷日志數(shù)量
官方提供的回滾段中undo槽的數(shù)量根據(jù)InnoDB頁面大小有關(guān):
從最新的MySQL8.0.27源碼實(shí)現(xiàn)中 storageinnobaseincludetrx0rseg.h:
/* Number of undo log slots in a rollback segment file copy 這里 UNIV_PAGE_SIZE正常頁面的大小 即 1024*/ #define TRX_RSEG_N_SLOTS (UNIV_PAGE_SIZE / 16) /* Maximum number of transactions supported by a single rollback segment 單個(gè)回滾段支持的最大事務(wù)數(shù)1024/2=512 */ #define TRX_RSEG_MAX_N_TRXS (TRX_RSEG_N_SLOTS / 2)
在默認(rèn)情況下page中又劃分了1024個(gè)slot槽(TRX_RSEG_N_SLOTS),每個(gè)slot又對(duì)應(yīng)到一個(gè)undo log對(duì)象,因此理論上InnoDB可以支持 128 * 512=65536個(gè)普通事務(wù)。
原理部分參考MySQL · 引擎特性 · InnoDB undo log 漫游
官方提供undbo回滾并發(fā)讀寫場(chǎng)景:
從上訴的原理中回到實(shí)際應(yīng)用場(chǎng)景中:
對(duì)于回滾段支持的能力,還是可觀的,但往往執(zhí)行大批量的回滾的時(shí)候非常慢。特別是在線處理過程中發(fā)現(xiàn)10w行回滾 有可能10分鐘這樣的情況。甚至更長(zhǎng)時(shí)間。
下面通過sysbench準(zhǔn)備5000w的單表數(shù)據(jù),在無負(fù)載下,大概刪除1分鐘,之后通過kill -9,強(qiáng)制停止方式回滾事務(wù):
明顯重新啟動(dòng)效果更加。
但kill -9 方式容易把數(shù)據(jù)頁損壞,存在很大的風(fēng)險(xiǎn)。日常當(dāng)中數(shù)據(jù)庫(kù)也有負(fù)載,可想而知,大事務(wù)回滾的代價(jià)非常大。
總結(jié)
應(yīng)盡量避免大的回退操作,非常消耗數(shù)據(jù)庫(kù)資源和性能,生產(chǎn)環(huán)境下會(huì)導(dǎo)致重大生產(chǎn)事故。避免不了大事務(wù)回滾,可以采取以下方式:
- 對(duì)于批量操作,可以分批提交 比如1000行 ~5000行之類的
- undo空間和全局臨時(shí)表空間 可以適當(dāng)?shù)恼{(diào)整。建議4個(gè)undo文件,全局ibtmp1初始化1G
- 高可用環(huán)境下,能確數(shù)據(jù)的一致性下,可以把從提升新主,提供服務(wù),等待大事務(wù)回滾。
- 極端情況下,可以通過 kill -9 重啟操作會(huì)因?yàn)閿?shù)據(jù)量非常大,導(dǎo)致mysql恢復(fù)緩慢,此時(shí)需要等待mysql進(jìn)行崩潰恢復(fù),根據(jù)數(shù)據(jù)量的不同,等待的時(shí)間也不同
- 如重新啟動(dòng)過程中,存在數(shù)據(jù)頁損壞或跳過回滾 ,可通過innodb_force_recovery=3(不執(zhí)行事務(wù)回滾操作。)
推薦學(xué)習(xí):mysql視頻教程