内射老阿姨1区2区3区4区_久久精品人人做人人爽电影蜜月_久久国产精品亚洲77777_99精品又大又爽又粗少妇毛片

MySQL中InnoDB內(nèi)部機(jī)制的示例分析

這篇文章主要介紹了MySQL中InnoDB內(nèi)部機(jī)制的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

成都創(chuàng)新互聯(lián)公司專注于企業(yè)成都營銷網(wǎng)站建設(shè)、網(wǎng)站重做改版、徐聞網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、HTML5建站、商城網(wǎng)站制作、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為徐聞等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

Read view

InnoDB支持MVCC多版本,其中RC(Read Committed)和RR(Repeatable Read)隔離級別是利用consistent read view(一致讀視圖)方式支持的。 所謂consistent read view就是在某一時刻給事務(wù)系統(tǒng)trx_sys打snapshot(快照),把當(dāng)時trx_sys狀態(tài)(包括活躍讀寫事務(wù)數(shù)組)記下來,之后的所有讀操作根據(jù)其事務(wù)ID(即trx_id)與snapshot中的trx_sys的狀態(tài)作比較,以此判斷read view對于事務(wù)的可見性。

Read view中保存的trx_sys狀態(tài)主要包括

  • low_limit_id:high water mark,大于等于view->low_limit_id的事務(wù)對于view都是不可見的

  • up_limit_id:low water mark,小于view->up_limit_id的事務(wù)對于view一定是可見的

  • low_limit_no:trx_no小于view->low_limit_no的undo log對于view是可以purge的

  • rw_trx_ids:讀寫事務(wù)數(shù)組

RR隔離級別(除了Gap鎖之外)和RC隔離級別的差別是創(chuàng)建snapshot時機(jī)不同。 RR隔離級別是在事務(wù)開始時刻,確切地說是第一個讀操作創(chuàng)建read view的;RC隔離級別是在語句開始時刻創(chuàng)建read view的。

創(chuàng)建/關(guān)閉read view需要持有trx_sys->mutex,會降低系統(tǒng)性能,5.7版本對此進(jìn)行優(yōu)化,在事務(wù)提交時session會cache只讀事務(wù)的read view。

下次創(chuàng)建read view,判斷如果是只讀事務(wù)并且系統(tǒng)的讀寫事務(wù)狀態(tài)沒有發(fā)生變化,即trx_sys的max_trx_id沒有向前推進(jìn),而且沒有新的讀寫事務(wù)產(chǎn)生,就可以重用上次的read view。

Read view創(chuàng)建之后,讀數(shù)據(jù)時比較記錄最后更新的trx_id和view的high/low water mark和讀寫事務(wù)數(shù)組即可判斷可見性。

如前所述,如果記錄最新數(shù)據(jù)是當(dāng)前事務(wù)trx的更新結(jié)果,對應(yīng)當(dāng)前read view一定是可見的。

除此之外可以通過high/low water mark快速判斷:

  • trx_id < view->up_limit_id的記錄對于當(dāng)前read view是一定可見的;

  • trx_id >= view->low_limit_id的記錄對于當(dāng)前read view是一定不可見的;

如果trx_id落在[up_limit_id, low_limit_id),需要在活躍讀寫事務(wù)數(shù)組查找trx_id是否存在,如果存在,記錄對于當(dāng)前read view是不可見的。

由于InnoDB的二級索引只保存page最后更新的trx_id,當(dāng)利用二級索引進(jìn)行查詢的時候,如果page的trx_id小于view->up_limit_id,可以直接判斷page的所有記錄對于當(dāng)前view是可見的,否則需要回clustered索引進(jìn)行判斷。

如果記錄對于view不可見,需要通過記錄的DB_ROLL_PTR指針遍歷history list構(gòu)造當(dāng)前view可見版本數(shù)據(jù)。

回滾段

InnoDB也是采用回滾段的方式構(gòu)建old version記錄,這跟Oracle方式類似。

記錄的DB_ROLL_PTR指向最近一次更新所創(chuàng)建的回滾段;每條undo log也會指向更早版本的undo log,從而形成一條更新鏈。通過這個更新鏈,不同事務(wù)可以找到其對應(yīng)版本的undo log,組成old version記錄,這條鏈就是記錄的history list。

分配rollback segment

MySQL 5.6對于沒有顯示指定READ ONLY事務(wù),默認(rèn)為是讀寫事務(wù)。在事務(wù)開啟時刻分配trx_id和回滾段,并把當(dāng)前事務(wù)加到trx_sys的讀寫事務(wù)數(shù)組中。

5.7版本對于所有事務(wù)默認(rèn)為只讀事務(wù),遇到第一個寫操作時,只讀事務(wù)切換成讀寫事務(wù)分配trx_id和回滾段,并把當(dāng)前事務(wù)加到trx_sys的讀寫事務(wù)數(shù)組中。

分配回滾段的工作在函數(shù)trx_assign_rseg_low進(jìn)行,分配策略是采用round-robin方式。

從5.6開始支持獨立的undo表空間,InnoDB支持128個undo回滾段,請參照第1篇文章。

  • rseg0:預(yù)留在系統(tǒng)表空間ibdata中

  • rseg1~rseg32:這32個回滾段存放于臨時表的系統(tǒng)表空間中

  • rseg33~rseg127:根據(jù)配置存放到獨立undo表空間中(如果沒有打開獨立Undo表空間,則存放于ibdata中)

trx_assign_rseg_low判斷,如果支持獨立的undo表空間,在undo表空間有可用回滾段的情況下避免使用系統(tǒng)表空間的回滾段。

rseg->skip_allocation為TRUE表示rseg所在的表空間要被truncate,應(yīng)該避免使用此rseg分配回滾段。此種情況,必須保證有至少2個活躍的undo表空間,并且至少2個活躍的undo slot。

分配成功時,遞增rseg->trx_ref_count,保證rseg的表空間不會被truncate。

臨時表操作不記redo log,最終調(diào)用get_next_noredo_rseg函數(shù)進(jìn)行分配;其他情況調(diào)用get_next_redo_rseg。

回滾段實際上是undo文件組織方式,每個回滾段維護(hù)了一個段頭頁(segment header),該page劃分了1024個slot(TRX_RSEG_N_SLOTS),每個slot對應(yīng)到一個undo log對象。

理論上,InnoDB最多支持 96 (128 - 32 /* temp-tablespace */) * 1024個普通事務(wù)。

但如果是臨時表的事務(wù),可能還需要多分配1個slot(臨時表的系統(tǒng)表空間)。

  • 只讀階段為臨時表分配的,在臨時表的系統(tǒng)表空間中分配

  • 讀寫階段在undo表空間分配

分配undo log

Insert數(shù)據(jù)只對當(dāng)前事務(wù)或者提交之后可見,所以insert的undo log在事務(wù)commit后就可以釋放了。

Update/delete的undo記錄通常用來維護(hù)old version記錄,為查詢提供服務(wù);只有當(dāng)trx_sys中沒有任何view需要訪問那個old version的數(shù)據(jù)時才可以被釋放。

InnoDB對insert和update/delete分配不同的undo slot

  • insert的undo slot記在trx->rsegs.m_redo.insert_undo,調(diào)用trx_undo_assign_undo分配

  • update的undo slot記在trx->rsegs.m_redo.undate_undo,調(diào)用trx_undo_assign_undo分配

trx_undo_assign_undo

I. 檢查cached隊列是否有緩存的undo log(內(nèi)存中數(shù)據(jù)結(jié)構(gòu)是trx_undo_t)

  • 如果存在,把這個undo log從cached隊列移除

  • reuse的邏輯:

    a.insert undo:重新初始化undo page的header信息(trx_undo_insert_header_reuse),并在redo log記一條MLOG_UNDO_HDR_REUSE日志

    b.update undo:在undo page的header上分配新的undo header(trx_undo_header_create),并在redo log記一條MLOG_UNDO_HDR_CREATE日志

  • 預(yù)留xid空間

  • 重新初始化undo(trx_undo_mem_init_for_reuse)把undo->state設(shè)置為TRX_UNDO_ACTIVE,并把undo->state寫入到第一個undo page的TRX_UNDO_SEG_HDR+TRX_UNDO_STATE位置上

注1:TRX_UNDO_SEG_HDR表示segment header起始o(jì)ffset 注2:undo segment與事務(wù)trx是一一對應(yīng)關(guān)系,undo segment header的狀態(tài)(TRX_UNDO_STATE)跟事務(wù)當(dāng)前狀態(tài)也是一一對應(yīng)的

如下圖(引自第1篇文章)

MySQL中InnoDB內(nèi)部機(jī)制的示例分析

undo segment是個獨立的段,每個undo segment包含1個header page(第1個undo page)和若干個記錄undo日志的undo page。

第1個undo page中存儲的是元信息: 首先存儲的是undo page的元信息,位于TRX_UNDO_PAGE_HDR到TRX_UNDO_SEG_HDR之間。

TRX_UNDO_PAGE_START:指向page中第一個undo log TRX_UNDO_PAGE_FREE:指向page中下一個undo log要寫到的位置 TRX_UNDO_PAGE_NODE:undo segment所有page組成一個雙向鏈表,每個page的TRX_UNDO_PAGE_NODE字段作為連接件,第一個undo page中的TRX_UNDO_PAGE_LIST作為表頭

 /* undo page header */ #define TRX_UNDO_PAGE_HDR FSEG_PAGE_DATA #define TRX_UNDO_PAGE_TYPE 0 /*!< TRX_UNDO_INSERT or
                    TRX_UNDO_UPDATE */ #define TRX_UNDO_PAGE_START 2 /*!< Byte offset where the undo log
                    records for the LATEST transaction
                    start on this page (remember that
                    in an update undo log, the first page
                    can contain several undo logs) */ #define TRX_UNDO_PAGE_FREE 4 /*!< On each page of the undo log this
                    field contains the byte offset of the
                    first free byte on the page */ #define TRX_UNDO_PAGE_NODE 6 /*!< The file list node in the chain
                    of undo log pages */ /*-------------------------------------------------------------*/ #define TRX_UNDO_PAGE_HDR_SIZE (6 + FLST_NODE_SIZE) /*!< Size of the transaction undo
                    log page header, in bytes */

之后是undo segment的元信息,位于TRX_UNDO_SEG_HDR到TRX_UNDO_SEG_HDR+TRX_UNDO_SEG_HDR_SIZE

TRX_UNDO_STATE:表示undo segment的狀態(tài),一個undo segment可以包含多個undo log,但至多只有1個active undo log,也就是最近的undo log TRX_UNDO_LAST_LOG:指向最近的undo log的header信息 TRX_UNDO_FSEG_HEADER:存儲的是undo segment對應(yīng)的file segment信息,在fseg_create_general中設(shè)置(4字節(jié)space id,4字節(jié)的page no,2字節(jié)的page offset)

undo segment從buffer pool移除被persist到磁盤時,就寫到file segment指定的位置上

 #define TRX_UNDO_SEG_HDR    (TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) #define TRX_UNDO_STATE      0   /*!< TRX_UNDO_ACTIVE, ... */ #define TRX_UNDO_LAST_LOG   2   /*!< Offset of the last undo log header on the segment header page, 0 if none */ #define TRX_UNDO_FSEG_HEADER    4   /*!< Header for the file segment which the undo log segment occupies */ #define TRX_UNDO_PAGE_LIST  (4 + FSEG_HEADER_SIZE) /*!< Base node for the list of pages in
                    the undo log segment; defined only on
                    the undo log segment's first page */ /*-------------------------------------------------------------*/ /** Size of the undo log segment header */ #define TRX_UNDO_SEG_HDR_SIZE   (4 + FSEG_HEADER_SIZE + FLST_BASE_NODE_SIZE)

再之后是undo log header信息,所有的undo log header都存儲在第一個undo page上。

II. 從cached隊列分配undo失敗時,需要真正分配一個undo segment(trx_undo_seg_create)

首先要從rseg分配一個slot(trx_rsegf_undo_find_free),每個rseg至多支持1024個slot。找到空slot返回index。

如果當(dāng)前rseg已滿,trx_undo_seg_create返回DB_TOO_MANY_CONCURRENT_TRXS向上層報錯,表示并發(fā)事務(wù)太多無法創(chuàng)建undo segment。

然后在rseg對應(yīng)的table space創(chuàng)建一個新的file segment,file segment信息記在segment header的TRX_UNDO_FSEG_HEADER(fseg_create_general)。

trx_undo_seg_create在創(chuàng)建file segment之后,把新創(chuàng)建segment的page no寫到rseg對應(yīng)slot上建立映射關(guān)系,并返回新創(chuàng)建segment的page。

file segment與undo segment的映射關(guān)系,還有rseg[slot]與file segment對應(yīng)page的映射關(guān)系都是在trx_undo_seg_create綁定的。cached undo不會更新這兩個映射關(guān)系。

III. trx_undo_seg_create返回的page上創(chuàng)建新的undo header;上層負(fù)責(zé)初始化trx_undo_t數(shù)據(jù)結(jié)構(gòu)

trx_undo_create為新創(chuàng)建的undo header創(chuàng)建內(nèi)存數(shù)據(jù)結(jié)構(gòu)trx_undo_t(trx_undo_mem_create),把undo->state設(shè)置為TRX_UNDO_ACTIVE。

IV. 分配好的trx_undo_t會加入到事務(wù)的insert_undo_list或者update_undo_list隊列上

寫入undo log

trx_undo_assign_undo分配undo之后,就可往其中寫入undo記錄。寫入的page來自undo->last_page_no,初始情況下等于hdr_page_no。

update undo包含一個重要的部分:記錄的當(dāng)前回滾段指針要寫到undo log里面,以便維護(hù)記錄的歷史數(shù)據(jù)鏈。

read view需要讀老版本數(shù)據(jù)時,會通過記錄中當(dāng)前的回滾段指針開始向前找到可見版本的數(shù)據(jù)。

完成Undo log寫入后,構(gòu)建新的回滾段指針并返回(trx_undo_build_roll_ptr),這個指針也就是clustered索引記錄的DB_ROLL_PTR。

回滾段指針包括rseg->id、日志所在的page no、以及page內(nèi)偏移量,需要記錄到clustered索引記錄中。這里rseg->id用來確定rseg->space,真正用于定位undo log位置的其實是<rseg->space, undo->page,undo->page_offset>三元組。

事務(wù)prepare

設(shè)置undo->state為TRX_UNDO_PREPARED,并把這個狀態(tài)寫到第一個undo page的(TRX_UNDO_SEG_HDR+TRX_UNDO_STATE)位置上。

除此之外,prepare階段還要更新xid信息。

事務(wù)commit

在事務(wù)commit階段,需要把undo->state設(shè)置為完成狀態(tài),并把undo加到undo segment的history list。正在提交的undo header被指向history list的第一項,表示當(dāng)前事務(wù)history list最近的undo。

undo->state完成狀態(tài)包括3種,在trx_undo_set_state_at_finish設(shè)置

  • undo只占一個page,而且第一個undo page已使用的空間小于3/4 (TRX_UNDO_PAGE_REUSE_LIMIT):狀態(tài)設(shè)置為TRX_UNDO_CACHED

  • 不滿足1的情況下,如果是insert_undo(TRX_UNDO_INSERT):狀態(tài)設(shè)置為TRX_UNDO_TO_FREE

  • 不滿足1和2的情況下,狀態(tài)設(shè)置為TRX_UNDO_TO_PURGE,表示undo可能需要purge線程清理

cached undo會被到cached隊列上,這個隊列就是trx_undo_assign_undo提到的cached隊列

設(shè)置完undo->state之后,需要把這個狀態(tài)寫入到第一個undo page的(TRX_UNDO_SEG_HDR+TRX_UNDO_STATE)位置上

把undo加到undo segment header的history list

Insert的old version沒有實際意義,所以insert undo在事務(wù)commit時就可以釋放了。

trx_undo_set_state_at_finish里面有cached策略,如果只占1個undo page,并且undo page已使用的空間不足pagesize的3/4可以被reuse,其實大部分insert undo都屬于這種情況。

Update undo需要維護(hù)history list。這里先提一下trx->no,它維護(hù)了事務(wù)trx commit順序,跟事務(wù)的trx_id一樣,也是使用max_trx_id遞增產(chǎn)生。

另外,purge_sys(purge的全局?jǐn)?shù)據(jù)結(jié)構(gòu))維護(hù)個最小堆,每個rollback segment第1次事務(wù)提交時向最小堆插入數(shù)據(jù),旨在找到trx_no最小的rollback segment進(jìn)行purge。后面每次處理完1個rseg后,會把下一個undo記錄的trx_no壓入到這個最小堆,作為rseg的cursor。

事務(wù)commit時按照trx->no順序,把事務(wù)當(dāng)前的undo log掛到undo segment history list的表頭,指向事務(wù)最近的undo log。

History list里的undo都是已提交事務(wù)的,當(dāng)前事務(wù)所修改的undo log都記錄在這里,按照從新->老方式排列,最老的undo log在尾部。

undo加入到history list的方式是:以undo log的TRX_UNDO_HISTORY_NODE作為連接件,加入到第一個undo page的TRX_RSEG_HISTORY。

一般來說,每次調(diào)用trx_purge_add_update_undo_to_history都會把undo加入到history list,只有在undo page無法被reuse時才更新history list大?。梢哉J(rèn)為是個優(yōu)化,最后一次更新history length)。

在此之后,trx_purge_add_update_undo_to_history會把undo log header的TRX_UNDO_TRX_NO更新為trx_no。

如果undo->del_marks是FALSE,這個函數(shù)也會更新TRX_UNDO_DEL_MARKS(undo segment創(chuàng)建或者reuse被初始化為TRUE),澄清這不是delete marker。

如果undo segment自創(chuàng)建以來(也可能是上次purge完成之后)中第1個事務(wù)commit,還需要更新purge有關(guān)的一些參數(shù),指向下次purge從哪里開始執(zhí)行。

老版本數(shù)據(jù)purge

舊版本數(shù)據(jù)不再被任何view訪問就可以被刪除了。5.6以上版本支持獨立purge線程,用戶可以通過參數(shù)Innodb_purge_threads設(shè)置purge線程個數(shù)。

有兩類purge線程:

  • coordinator thread:srv_purge_coordinator_thread,全局只有1個

  • worker thread:srv_worker_thread,系統(tǒng)有innodb_purge_threads - 1個

coordinator thread負(fù)責(zé)啟動worker thread參與到purge工作中。

增加purge線程的策略是:trx_sys->rseg_history_len比上次循環(huán)變大了或者rseg_history_len超過某一閾值,需要引進(jìn)更多的worker thread。

減少purge線程的策略是:如果之前使用多個purge 線程,trx_sys->rseg_history_len并沒有變大,可能需要減少worker thread。

在進(jìn)行purge之前,首先要確定purge線程要做哪些工作,也就是說哪些undo log可以被purged。

purge也是通過read view來確定工作范圍,被稱為purge view。如果系統(tǒng)有活躍read view,就選取最老的read view作為purge view。

如果不存在就給trx_sys的狀態(tài)打個snapshot,作為purge view,可以被purge的undo log其trx_no一定是小于系統(tǒng)中所有已提交事務(wù)的trx->no。

這里插一句,在事務(wù)commit時,會把產(chǎn)生的trx->no加入到trx_sys->serialisation_list鏈表,這個鏈表是按照trx->no升序次序排列,也就是維護(hù)了trx commit順序。

InnoDB初始化的時候會初始化purge_sys數(shù)據(jù)結(jié)構(gòu),其中一個工作就是創(chuàng)建purge graph。

這是總共3層結(jié)構(gòu)的圖:

  • 第1層是fork節(jié)點

  • 第2次是thrd節(jié)點(表示purge thread)

  • 第3層是node節(jié)點(表示purge task)

所有的thrd節(jié)點被鏈入到fork->thrs鏈表中;fork地址存儲在purge_sys->query,可以通過purge_sys直接訪問。

執(zhí)行purge的時候總是遍歷purge_sys->query->thrs鏈表,給每個purge線程分配purge任務(wù)(trx_purge_attach_undo_recs)。

解析undo log的調(diào)用路徑如下:

 srv_purge_coordinator_thread -> srv_do_purge -> trx_purge ->
        trx_purge_attach_undo_recs -> trx_purge_fetch_next_rec -> 
               trx_purge_get_next_rec

purge_sys->next_stored為FALSE時,表示rseg_iter當(dāng)前指向的rseg無效,需要把rseg_iter移到下一個有效的rseg(TrxUndoRsegsIterator::set_next)。

purge_sys->purge_queue維護(hù)了一個最小堆,每次pop最頂元素,可以得到trx_no最小的rollback segment(TrxUndoRsegsIterator::set_next)。

5.7支持臨時表的noredo的rollback segment,set_next遇到redo rollback segment和noredo rollback segment同時存在的情況會一股腦把這兩個rollback segment都pop出來加入到 purge_sys->rseg_iter->m_trx_undo_rsegs數(shù)組中,也在TrxUndoRsegsIterator::set_next實現(xiàn)。

如果沒有rollback segment需要purge話,purge_sys->rseg設(shè)置為NULL,purge線程會去睡眠(trx_purge_choose_next_log)。

一般情況下都是有rollback segment需要處理的,purge_sys->rseg更新成purge_sys->rseg_iter->m_trx_undo_rsegs的第1項(至多2項)。

purge_sys中的相應(yīng)成員也要更新,指向當(dāng)前rseg上次purge到的位置(TrxUndoRsegsIterator::set_next)。

update undo的del_marks域正常情況下都是TRUE,因為update/delete操作都需要對old value進(jìn)行標(biāo)記刪除。

如果purge_sys->rseg->last_del_marks是FALSE的話,表示這是一個dummy的undo log,不需要做物理刪除。這種情況下,把purge_sys->offset設(shè)置成0,做個標(biāo)記表示這個undo log不需要被purged(trx_purge_read_undo_rec)。

正常情況下purge_sys->rseg->last_del_marks是TRUE,可以通過<purge_sys->rseg->space, purge_sys->hdr_page_no, purge_sys->hdr_offset>讀取undo log記錄(trx_purge_read_undo_rec)。

并把purge_sys以下四個域設(shè)置成undo log記錄相應(yīng)的信息(trx_purge_read_undo_rec)。

 purge_sys->offset = offset; /* undo log記錄的offset */ purge_sys->page_no = page_no; /* undo log記錄的pageno */ purge_sys->iter.undo_no = undo_no; /* undo log記錄的undo_no,trx內(nèi)部undo的序列號 */ purge_sys->iter.undo_rseg_space = undo_rseg_space; /* undo log的tablespace */

為了保證purge_sys以上4個域一定是指向下一個有效undo log,每次讀取undo log時都會捎帶著讀取下一個undo log,并把上面這四個域更新為下一個undo log的信息,方面后續(xù)訪問(trx_purge_get_next_rec)。

如果是dummy undo,trx_purge_get_next_rec會去讀prev_undo(trx_purge_rseg_get_next_history_log),用prev_log信息更新rseg中下一個purge信息。

在此之后,還會把rseg->last_trx_no壓入最小堆,待后面繼續(xù)處理這個rseg。 然后調(diào)用trx_purge_choose_next_log選擇下一個處理的rseg,并讀取第一個undo log(trx_purge_get_next_rec)。

就這樣挨個讀取undo log,trx_purge_attach_undo_recs中有一個大循環(huán),每次調(diào)用trx_purge_fetch_next_rec讀到一個undo log后,把它存放到purge節(jié)點(purge graph的第三級節(jié)點) node->undo_recs數(shù)組里面,循環(huán)下一次執(zhí)行切換到下一個thr(purge 線程)。

循環(huán)的結(jié)束條件是:

  • 沒有新的undo log

  • 處理過的undo log達(dá)到batch size(一般是300)

達(dá)到循環(huán)結(jié)束條件后,trx_purge_attach_undo_recs返回。如果n_purge_threads > 1 (需要worker線程參與purge),coordinator線程會以round-robin方式啟動n_purge_threads - 1個worker線程。

不管有沒有worker線程參與purge,coordinator線程都會調(diào)用que_run_threads(在trx_purge上下文)去處理purge任務(wù)。

purge任務(wù)如何處理呢?通俗的說purge就是刪除被標(biāo)記delete marker的記錄項。

大致過程如下:

 srv_purge_coordinator_thread -> srv_do_purge -> trx_purge ->
        que_run_threads -> que_run_threads_low -> que_thr_step
               row_purge_step -> row_purge -> row_purge_record ->
                       row_purge_del_mark -> row_purge_remove_sec_if_poss

一般刪除的原則是先刪除二級索引再刪除clustered索引(row_purge_del_mark)。

另一種情況是聚集索引in-place更新了,但二級索引上的記錄順序可能發(fā)生變化,而二級索引的更新總是標(biāo)記刪除 + 插入,因此需要根據(jù)回滾段記錄去檢查二級索引記錄序是否發(fā)生變化,并執(zhí)行清理操作(row_purge_upd_exist_or_extern)。

前面提到過在parse undo log時,可能遇到dummy undo log。返回到row_purge執(zhí)行時需要判讀是否是dummy undo,如果是就什么也不做。

truncate undo space

trx_purge在處理完一個batch(通常是300)之后,調(diào)用trx_purge_truncate_historypurge_sys對每一個rseg嘗試釋放undo log(trx_purge_truncate_rseg_history)。

大致過程是:把每個purge過的undo log從history list移除,如果undo segment中所有的undo log都被釋放,可以嘗試釋放undo segment,這里隱式釋放file segment到達(dá)釋放存儲空間的目的。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“MySQL中InnoDB內(nèi)部機(jī)制的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!

網(wǎng)站欄目:MySQL中InnoDB內(nèi)部機(jī)制的示例分析
分享鏈接:http://www.rwnh.cn/article4/ghdpoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計、用戶體驗、品牌網(wǎng)站制作、手機(jī)網(wǎng)站建設(shè)、品牌網(wǎng)站建設(shè)、營銷型網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)
西青区| 东莞市| 无为县| 合肥市| 策勒县| 芜湖市| 化隆| 江源县| 巴林右旗| 永吉县| 临城县| 将乐县| 广元市| 自治县| 竹溪县| 密云县| 临西县| 军事| 柳林县| 峨眉山市| 新疆| 扶风县| 泸西县| 新源县| 六盘水市| 紫金县| 中西区| 莆田市| 灵武市| 高雄县| 广宁县| 佛学| 泉州市| 宜春市| 辽阳市| 左贡县| 克山县| 贵溪市| 固镇县| 无棣县| 晋中市|