MySQL核心InnoDB儲存引擎(卷1)筆記

志_祥發表於2014-11-02

MySQL核心InnoDB儲存引擎(卷1)

概覽

基本資料結構和演算法

同步機制

  1. rw-lock/latch
    1. s-/x-:x-可遞迴,s-不可?;以spin獲得,一段時間後進入wait array(訊號量?)
  2. p38 若sync_primary_wait_array中1000個cell都已分配,則ut_error觸發crash
    1. 當持有latch的執行緒釋放latch後,呼叫sync_array_signal_object喚醒等待執行緒

重做日誌

  1. p42 redo log原來保證事務的永續性(D),undo log用於回滾和MVCC
  2. innodb_flush_log_at_trx_commit=0/1/2
  3. redo log VS. bin log
    1. 前者記錄的是頁的物理邏輯操作日誌
    2. 設計思想:物理日誌記錄頁內的修改(old-new value),邏輯日誌記錄對錶的操作(insert/delete)
  4. LSN(表示事務寫入redo log的位元組量?)
    1. 對‘檢查點’,表示重新整理到磁碟的位置?——不管怎麼說,LSN有一種‘隨時間單調變化’的性質
  5. 檢查點:將緩衝池中的頁重新整理到磁碟
    1. sharp
    2. fuzzy*
  6. redo日誌的大小是固定的(3GB)->歸檔日誌
  7. ib_logfile<N>
  8. redo日誌塊(512B-12-8)
    1. 和磁碟扇區大小一樣,保證原子性,不需要double write?
  9. 重做日誌組*
  10. 組提交:fsync -> log_flush_up_to 會對最後一個日誌塊進行復制
  11. 恢復:recovery_from_checkpoint_start
    1. 表空間第一個頁頭部的FIL_PAGE_FILE_FLUSH_LSN記錄了資料庫關閉時最後重新整理頁的LSN
    2. recv_parse_or_apply_log_rec_body
    3. recv_add_to_hash_table
    4. recv_recover_page
    5. recv_read_in_area 判斷頁所在相鄰的32個頁?

mini-transaction(mtr)

  1. FIX rules:修改頁之前需要持有該頁的latch
  2. WAL
    1. 每個頁需要有一個LSN?LSN溢位怎麼辦?
  3. Force-Log-at-Commit
  4. mtr_t mtr; mtr_start(&mtr); ... mtr_commit(&mtr);
    1. 提交時若mtr->modified==TRUE,先修改緩衝池中的頁*1,然後釋放log_sys->mutex(這是一個熱點)
      1. *1 log_reserve_and_write_fast/log_write_slow 快速/慢速2個路徑
    2. 更新多行記錄時,MLOG_MULTI_REC_END

儲存管理

  1. 頁:(space_id, offset) 16KB
  2. 1 extent = 64 連續的page
    1. space header
  3. 段(segment)
    1. 每張使用者表至少2個段:聚集索引(B+樹)的葉子節點和非葉子節點段
    2. 一個段最多可以管理32個獨立的頁,和若干區
  4. 表空間
  5. 資料結構:fil_system/space/node_struct
  6. 4個非同步I/O執行緒:非同步讀、非同步寫、插入快取、重做日誌

記錄

  1. 物理記錄
    1. p102 使用者記錄的heap no總是從2開始
      1. 偽記錄:Infimum/Supremum(感覺將像是雙連結串列的first/last)
    2. p103 VARCHAR型別的NULL不佔用磁碟空間,而CHAR NULL用0x00填充
    3. 大記錄:BLOB/TEXT(溢位頁,extern屬性)
  2. 邏輯記錄
    1. dtuple_struct,對大記錄是big_rec_struct
    2. B+樹索引只定位頁,頁內記錄需要二分掃描
      1. mtype/prtype
  3. 行記錄版本(MVCC只是列?):通過隱藏的事務ID列
    1. read_view_struct
      1. low/up_limit_id
      2. trx_ids, n_trx_ids
      3. creator
    2. p114 函式read_view_sees_trx_id用來判斷當前事務是否可以讀記錄的當前版本,不是,則row_sel_build_prev_vers_for_mysql

索引頁

  1. Page Header
    1. 頁內記錄根據主鍵是邏輯順序,不是物理順序
  2. Page Directory(定位記錄在頁內的位置)
    1. slot?offset的主鍵逆序記錄
  3. Page Cursor*

  1. p136 理論上,隔離級別越低,事務請求的鎖越少或保持鎖的時間越短
  2. 幻讀:謂詞鎖 --> key-range locking --> next/previous-key locking
  3. p138 意向鎖:意味著事務希望在更細粒度上加鎖
    1. InnoDB是行級鎖,不會阻止全表掃描以外的請求
  4. lock_rec_struct = { space, page_no, n_bits }
    1. 所有鎖物件通過kernel_mutex進行保護(又一個熱點!)
      1. 優化:細粒度拆分?
  5. p144 LOCK_GAP(代表範圍鎖不包含端點)
  6. 顯式鎖和隱式鎖**(略)
  7. 行鎖的維護*(重點,略)
    1. 插入
    2. 更新
    3. PURGE
    4. 一致性的鎖定讀
    5. 頁的分裂
    6. 頁的合併
  8. 自增鎖(atomic?)
  9. 死鎖*

B+樹索引

  1. 聚集 / 輔助
  2. 分裂操作:btr_page_split_and_insert
  3. 合併:btr_compress
  4. 查詢:btr_cur_search_to_nth_level
    1. p203 對唯一約束的鍵值,需要使用模式PAGE_CUR_GE,而不是LE
    2. latch_mode
    3. cursor
  5. DML操作
    1. 樂觀插入:btr_cur_optimistic_insert
    2. 非主鍵更新(主要是列的大小會不會發生變化)
      1. btr_cur_optimistic_update --> btr_cur_pessimistic_update(例略)
    3. 主鍵更新
      1. 刪除
  6. 持久遊標 btr_pcur_struct
  7. 自適應雜湊索引*

Insert Buffer

  1. 將多次插入合併為一次操作(提高了非唯一約束輔助索引的插入效能)
  2. p237 實現最為困難的在於對死鎖的處理
    1. 頁邏輯層次劃分:非IB頁、IB非bitmap頁、bitmap頁
    2. p241 非同步I/O執行緒可能引起死鎖問題 --> rw_lock_x_lock_move_ownership

緩衝池

  1. LRU、Free和Flush連結串列
  2. 預讀
    1. p258 隨機預讀
      1. 要滿足32個頁中9個已經訪問過且都是活躍的才可能觸發
    2. 線性預讀*
    3. 邏輯預讀
  3. 頁的重新整理
    1. 部分寫問題(?) --> double write(存在於記憶體的表空間,大小為2MB,這意味著最多128頁/次重新整理)

事務處理

  1. 分類:扁平、帶儲存點的扁平、鏈、巢狀、分散式
  2. 事務系統段*
  3. doublewrite段*
  4. undo日誌儲存
    1. 一致性的非鎖定讀
      1. p282 讀取快照不需要加鎖
    2. undo日誌實現:回滾段 + undo段
      1. trx_undo_struct
  5. undo記錄
  6. purge*
  7. rollback
    1. 7B roll_ptr隱藏列 {rseg_id(1), page_no(4), offset(2)}
    2. 3個回滾型別:TRX_SIG_{TOTAL_ROLLBACK, ROLLBACK_TO_SAVEPT, ERROR_OCCURRED}
  8. commit

資料字典

服務管理

相關文章