0、undo物理存儲研究html
1>ibdata第五個數據塊(系統事務表)中存儲着128個undo段的段頭塊的地址mysql
2>每個undo段頭塊有1024行,兩行記錄一個事務,一共能夠記錄512個事務sql
3>一個數據行中存放XID、rollpointr數據庫
4>一個數據行被修改服務器
1.新的事務ID併發
2.新的rollpointrmvc
3.修改後數據分佈式
上面三部分數據都會進入到回滾塊中。詳細見:事務工做流程……高併發
一、避免髒讀
1>在操做任何數據以前,首先將數據備份到undo頁中,而後再進行數據的修改;
2>不能看到其餘會話未提交的數據;
3>當要讀取被修改數據頁數據行時,會指向備份在undo頁中的數據,而避免髒讀。
二、事務的回滾
undo最基本的做用是rollback,舊數據先放到undo裏面存放,等rollback時候再將undo裏面的數據回滾回來。
三、DML不阻塞讀
提升併發,若是別的用戶正在修改某數據頁,事務沒有提交,現須要讀該數據頁,發現事務沒有提交,就根據數據行上的rollpointer找到原來的數據(在undo頁上),結合該數據頁將數據返給用戶。
四、MVCC(一致性讀)
多版本控制Multiversion Concurrency Control
五、崩潰恢復(回滾)
自動回滾未提交事務;
redo前滾,undo回滾,未提交事務主動回滾,未提交事務信息在事務槽裏寫着。數據庫在運行期間,忽然崩了,數據庫啓動以後,須要redo前滾,就會有不少未提交的事務(事務的會話斷了,不可能繼續完成了,就須要對未提交事務回滾了 )也滾回來了:讀取未提交事務事務槽信息,把未提交事務回滾。
一、分配一個事務ID,事務ID依次遞增
二、分配一個事務槽,將事務信息寫入事務槽中
三、開始修改數據行,數據行中存儲事務ID、修改前數據所使用的回滾塊地址
四、回滾塊中存放修改前的數據
五、屬於一個事務的各個回滾塊連接起來
六、回滾段段頭塊中的地址指向回滾塊鏈表中的最後一個回滾塊
七、一個回滾塊只能存放一個事務的數據
八、事務提交就是在事務槽中將事務狀態改爲已提交
理解不深(轉自:http://www.cnblogs.com/chenpingzhao/p/5065316.html)
一、MVCC的幾個特色:
1>每行數據都存在一個版本,每次數據更新時都更新該版本
2>修改時Copy出當前版本隨意修改,各個事務之間無干擾
3>保存時比較版本號,若是成功(commit),則覆蓋原記錄;失敗則放棄copy(rollback)
也就是每行都有版本號,保存時根據版本號決定是否成功,聽起來含有樂觀鎖的味道;
二、非阻塞讀Innodb的實現方式:
4>事務以排他鎖的形式修改原始數據
5>把修改前的數據存放於undo log,經過回滾指針與主數據關聯
6>修改爲功(commit)啥都不作,失敗則恢復undo log中的數據(rollback)
三、區別理解
兩者最本質的區別是,當修改數據時是否要排他鎖定;
Innodb的實現真算不上MVCC,由於並無實現核心的多版本共存,undo log中的內容只是串行化的結果,記錄了多個事務的過程,不屬於多版本共存。但理想的MVCC是難以實現的,當事務僅修改一行記錄使用理想的MVCC模式是沒有問題的,能夠經過比較版本號進行回滾;但當事務影響到多行數據時,理想的MVCC據無能爲力了。
好比,若是Transaciton1執行理想的MVCC,修改Row1成功,而修改Row2失敗,此時須要回滾Row1,但由於Row1沒有被鎖定,其數據可能又被Transaction2所修改,若是此時回滾Row1的內容,則會破壞Transaction2的修改結果,致使Transaction2違反ACID。
理想MVCC難以實現的根本緣由在於企圖經過樂觀鎖代替二段提交。修改兩行數據,但爲了保證其一致性,與修改兩個分佈式系統中的數據並沒有區別,而二提交是目前這種場景保證一致性的惟一手段。二段提交的本質是鎖定,樂觀鎖的本質是消除鎖定,兩者矛盾,故理想的MVCC難以真正在實際中被應用,Innodb只是借了MVCC這個名字,提供了讀的非阻塞而已。
redo前滾、undo回滾……
一、兩個保證
1>數據庫保證全部已提交事務的redolog都寫入到了redo logfile中
2>數據庫保證全部髒塊的redolog都早redo logfile中,只有髒塊寫入磁盤之後,redo log才能被覆蓋
結論:redo log有足夠的能力將該有的髒塊都構造出來
二、redo log如何肯定使用哪些日誌來構造髒塊
1>起點:checkpoint開始
1.innodb buffer pool中存在一條flush list鏈表
2.這個鏈表最舊的那一端對應的redo log就是未來數據庫崩潰恢復redolog前滾的起點
3.clean線程週期性的將須要flush list最舊的那一個髒塊對應的redo log地址寫入到ibdata中
2>終點:redo log current最後一條日誌
三、崩潰恢復的過程
第一個階段是前滾:
前滾對應的redo log的啓動和終點已經肯定:redolog不懼怕多跑,由於redolog有版本,數據塊有版本,若是redolog比數據塊還要舊,就採用空跑的方式
第二個階段是回滾:
崩潰時沒有提交的事務也會被回滾回來,這些事務都屬於死事務,由於這些事務對應的用戶會話已經結束,後續讀到對應的數據塊,發現數據塊上有未提交事務,讀取未提交事務對應的事務信息,發現已是死事務,主動回滾這個數據塊;
碰到死事務對應的數據塊,誰使用誰回滾。
一、長事務的危害
開始一個事務,長時間不提交,全部的數據都須要undo去保存,可能產生不少undo數據,並且還不能被清空覆蓋,一直保存到該事務提交。很嚴重。
二、大事務的危害
修改批量的數據,佔用過多的undo頁(產生undo數據主要是delete產生的,但MySQL對delete作了優化,添加deleted_flag標誌位,減小delete對undo的使用),因此危害不是很大,並且正常的事務場景也不會出現大事務。
三、如何判斷大事務和長事務
mysql> desc information_schema.INNODB_TRX;
關鍵參數:
1.trx_started:事務開始的時間,若是時間較當前差很遠說明是長事務
2.trx_rows_modified:事務修改的行數量,若是值很大說明是大事務
3.trx_mysql_thread_id:該事務所對應的線程id(kill線程清理事務)
四、解決棘手的大事務、長事務
處理大事務:kill -9 mysql_process_id:處理大事務,就直接幹掉mysql實例,不會主動去回滾因此速度塊,而後重啓。(除非無可奈何,不然不那麼幹,生產環境重啓服務器是天大的事情)
處理長事務:若是開始的時間不是很長,而且行數不是不少,直接kill掉該事務所在的線程。(在數據庫裏kill,可能反應慢)
一、實現undo分離
在MySQL5.5以及以前,除了數據量天然增加以外,一旦出現大事務,其所使用的undo log佔用的空間就會一直在ibdata1裏面存在,即便這個事務已經關閉。隨着數據庫上線時間愈來愈長,ibdata1文件會愈來愈大,物理備份文件愈來愈大……
MySQL 5.6增長了以下參數,能夠把undo log從ibdata1移出來單獨存放。
mysql> show variables like '%undo%'; +--------------------------+------------+
| Variable_name | Value |
+--------------------------+------------+
| innodb_max_undo_log_size | 1073741824 |
| innodb_undo_directory | ./ |
| innodb_undo_log_truncate | ON |
| innodb_undo_logs | 128 |
| innodb_undo_tablespaces | 3 |
+--------------------------+------------+
5 rows in set, 1 warning (0.00 sec)
1> innodb_undo_directory:
指定單獨存放undo表空間的目錄,默認爲.(即datadir),能夠設置相對路徑或者絕對路徑。該參數實例初始化以後雖然不可直接改動,可是能夠經過先停庫,修改配置文件,而後移動undo表空間文件的方式去修改該參數;
2> innodb_undo_tablespaces:
指定單獨存放的undo表空間個數,例如若是設置爲3,則undo表空間爲undo00一、undo00二、undo003,每一個文件初始大小默認爲10M。該參數實例初始化以後不可改動;
3> innodb_undo_logs:
指定回滾段的個數(早期版本該參數名字是innodb_rollback_segments),默認128個。每一個回滾段可同時支持1024個在線事務。這些回滾段會平均分佈到各個undo表空間中。該變量能夠動態調整,可是物理上的回滾段不會減小,只是會控制用到的回滾段的個數。
操做undo分離:實際使用方面,在初始化實例以前,咱們只須要設置innodb_undo_tablespaces參數(建議大於等於3)便可將undo log設置到單獨的undo表空間中。
二、在線收縮undo表空間
MySQL 5.7引入了新的參數,innodb_undo_log_truncate,開啓後可在線收縮拆分出來的undo表空間,支持動態設置。
1>實如今線收縮undo的條件
1.innodb_undo_tablespaces>=2:由於truncate undo表空間時,該文件處於inactive狀態,若是隻有1個undo表空間,那麼整個系統在此過程當中將處於不可用狀態;
2.innodb_undo_logs>=35(默認128):由於在MySQL 5.7中,第一個undo log永遠在共享表空間中,另外32個undo log分配給了臨時表空間(即ibtmp1),至少還有2個undo log才能保證2個undo表空間中每一個裏面至少有1個undo log;
2>知足以上2個條件後
innodb_undo_log_truncate=ON,便可開啓undo表空間的自動truncate
1.innodb_max_undo_log_size:undo表空間文件超過此值即標記爲可收縮,默認1G,truncate以後空間縮小到10M;
2.innodb_purge_rseg_truncate_frequency:指定purge操做被喚起多少次以後才釋放rollback segments。當undo表空間裏面的rollback segments被釋放時,undo表空間纔會被truncate。(最大是128,最小是1,默認爲128)該參數越小,undo表空間被嘗試truncate的頻率越高。