## 前言
在前面幾期月報我們介紹了undo log、redo log以及InnoDB如何崩潰恢復來實現數據ACID的相關知識。本期我們介紹另外一種重要的數據變更日志,也就是InnoDB change buffer。 Change buffer的主要目的是將對二級索引的數據操作緩存下來,以此減少二級索引的隨機IO,并達到操作合并的效果。
在MySQL5.5之前的版本中,由于只支持緩存insert操作,所以最初叫做insert buffer,只是后來的版本中支持了更多的操作類型緩存,才改叫change buffer,這也是為什么代碼中有大量的ibuf前綴開頭的函數或變量。為了表達方面,本文也將change buffer縮寫為ibuf。
由于歷史上ibuf的數據格式曾發生過多次變化,本文討論的相關內容基于如下設定:
版本為5.5及之后的版本,不涉及舊版本的邏輯,innodb_change_buffering 設置為ALL,表示緩存所有操作。
## ibuf btree
change buffer的物理上是一顆普通的btree,存儲在ibdata系統表空間中,根頁為ibdata的第4個page(FSP_IBUF_TREE_ROOT_PAGE_NO)。
一條ibuf 記錄大概包含如下列:

ibuf btree通過三列(space id, page no , counter)作為主鍵來唯一決定一條記錄,其中counter是一個遞增值,目的是為了維持不同操作的有序性,例如可以通過counter來保證在merge時執行如下序列時的循序和用戶操作順序是一致的:INSERT x, DELETE-MARK x, INSERT x。
在插入ibuf記錄前我們是不知道counter的值的,因此總是先將對應tuple的counter設置為0xFFFF,然后將cursor以模式PAGE_CUR_LE定位到小于等于(space id, page no, 0xFFFF)的位置,新記錄的counter為當前位置記錄counter值加1。
ibuf btree最大默認為buffer pool size的25%,當超過25%時,可能觸發用戶線程同步縮減ibuf btree。為何要將ibuf btree的大小和buffer pool大小相關聯呢 ? 一個比較重要的原因是防止ibuf本身占用過多的buffer pool資源。
## ibuf bitmap
由于ibuf 緩存的操作都是針對某個具體page的,因此在緩存操作時必須保證該操作不會導致空page 或索引分裂。
針對第一種情況,即避免空page,主要是對purge線程而言,因為只有purge線程才會去真正的刪除二級索引上的物理記錄。在準備插入類型為IBUF_OP_DELETE的操作緩存時,會預估在apply完該page上所有的ibuf entry后還剩下多少記錄(`ibuf_get_volume_buffered`),如果只剩下一條記錄,則拒絕本次purge操作緩存,改走正常的讀入物理頁邏輯。
針對第二種情況,InnoDB通過一種特殊的page來維護每個數據頁的空閑空間大小,也就是ibuf bitmap page,該page存在于每個ibd文件中,具有固定的page no,其文件結構如下圖所示:

ibuf bitmap使用4個bit來描述一個page:
1. IBUF_BITMAP_FREE:使用2個bit來描述空閑空間大小,以16KB的page size為例,能表示的空閑空間范圍為0(0 bytes)、1(512 bytes)、2(1024 bytes)、3(2048 bytes)。很顯然,能夠緩存的二級索引記錄最大不可能超過2048字節。
由于只有INSERT操作才可能導致page記錄滿,因此只需要對IBUF_OP_INSERT類型的操作進行判斷:
ibuf_insert_low:
~~~
if (op == IBUF_OP_INSERT) {
ulint bits = ibuf_bitmap_page_get_bits(
bitmap_page, page_no, zip_size, IBUF_BITMAP_FREE,
&bitmap_mtr);
if (buffered + entry_size + page_dir_calc_reserved_space(1)
> ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
/* Release the bitmap page latch early. */
ibuf_mtr_commit(&bitmap_mtr);
/* It may not fit */
do_merge = TRUE;
ibuf_get_merge_page_nos(FALSE,
btr_pcur_get_rec(&pcur), &mtr,
space_ids, space_versions,
page_nos, &n_stored);
goto fail_exit;
}
}
~~~
其中`ibuf_bitmap_page_get_bits`函數根據space id 和page no 獲取對應的bitmap page,找到空閑空間描述信息;如果本次插入操作可能超出限制,則從當前cursor位置附近開始,觸發一次異步的ibuf merge,目的是盡量將當前page的緩存操作做一次合并。
在正常的對物理頁的DML過程中,如果page內空間發生了變化,總是需要去更新對應的IBUF_BITMAP_FREE值。參考函數:`btr_compress`、`btr_cur_optimistic_insert`。
2. IBUF_BITMAP_BUFFERED:用于表示該page是否有操作緩存,在`ibuf_insert_low`函數中,準備插入ibuf btree前設置成true。二級索引物理頁讀入內存時會根據該標記位判斷是否需要進行ibuf merge操作。
3. IBUF_BITMAP_IBUF:表示該數據頁是否是ibuf btree的一部分,該標記位主要用于異步AIO讀操作。InnoDB專門為change buffer模塊分配了一個后臺AIO線程,如果page屬于change buffer的b樹,則使用該線程做異步讀,參考函數:`ibuf_page_low`
## 操作類型
InnoDB change buffer可以對三種類型的操作進行緩存:INSERT、DELETE-MARK 、DELETE操作,前兩種對應用戶線程操作,第三種則由purge操作觸發。
用戶可以通過參數innodb_change_buffering來控制緩存何種操作:
~~~
/** Allowed values of innodb_change_buffering */
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
"none", /* IBUF_USE_NONE */
"inserts", /* IBUF_USE_INSERT */
"deletes", /* IBUF_USE_DELETE_MARK */
"changes", /* IBUF_USE_INSERT_DELETE_MARK */
"purges", /* IBUF_USE_DELETE */
"all" /* IBUF_USE_ALL */
};
~~~
innodb_change_buffering默認值為all,表示緩存所有操作。注意由于在二級索引上的更新操作總是先delete-mark,再insert新記錄,因此update會產生兩條ibuf entry。
## 緩存條件
只有滿足一定條件時,操作才會被緩存,所有對ibuf操作的判斷,都從`btr_cur_search_to_nth_level`入口,該函數用于定位到btree上滿足條件的記錄,大概的判斷條件如下:
1. 用戶設置了選項innodb_change_buffering;
2. 只有葉子節點才會去考慮是否使用ibuf;
3. 對于聚集索引,不可以緩存操作;
4. 對于唯一二級索引(unique key),由于索引記錄具有唯一性,因此無法緩存插入操作,但可以緩存刪除操作;
5. 表上沒有flush 操作,例如執行flush table for export時,不允許對表進行 ibuf 緩存 (通過`dict_table_t::quiesce`?進行標識)
參考函數:`ibuf_should_try`:
當滿足ibuf緩存條件時,會使用兩種模式去嘗試獲取數據頁:
~~~
BUF_GET_IF_IN_POOL: 如果數據頁在內存中,則獲取page并返回,否則返回NULL;
BUF_GET_IF_IN_POOL_OR_WATCH:如果數據頁在內存中,則獲取page并返回,否則為請求的page設置一個`sentinel`(buf_pool_watch_set),相當于標記這個page,表示這個page上的記錄正在被purge。(下一小節介紹)
~~~
前者是前臺用戶線程觸發,后者為purge線程在物理清除無效數據時觸發,如果數據已經在內存中了,則不進行緩存。隨后進入函數ibuf_insert,經過一系列的檢查后(不可產生空page 和索引分裂、未超出最大ibuf size限制)執行操作緩存。
## purge操作緩存
對于purge操作,當page不存在于內存時設置的sentinel是什么鬼?它是如何設置的,什么時候會被清理掉,這幾個問題涉及到purge操作的緩存流程:
1. 如何設置sentinel
當purge線程嘗試讀入page時,若數據頁不在buffer pool中,則調用函數`buf_pool_watch_set`,分為兩步:
* Step1: 首先檢查page hash,如果存在于page hash中:1)若未被設置成sentinel (別的線程將數據頁讀入內存時會清理掉對應標記),返回數據頁;2)否則返回NULL;
* Step2: 若page hash中不存在,則從`buf_pool_t::watch`數組中找到一個空閑的(狀態為BUF_BLOCK_POOL_WATCH)page控制結構體對象buf_page_t,將其狀態設置為BUF_BLOCK_ZIP_PAGE,初始化相關變量,并插入到page hash中。`buf_pool_t::watch`數組的大小為purge線程的個數,這意味著即使所有purge線程同時訪問同一個buffer pool instance,總會擁有一個空閑的watch數組對象。
2. 判斷是否可以緩存purge操作
當設置sentinel并返回后,在決定緩存purge之前,需要去判斷是否有別的線程對同一條記錄緩存了新的操作,舉個簡單的例子:
* Step 1: delete-mark X (sec index) //session 1
* Step 2: insert X (clust index) //session 1
* Step 3: delete X(sec index) //purge thread
* Step 4: insert X (sec index) //session 1
如果二級索引頁在內存中,那么Step 3 和Step4必然是有序的,因為需要獲取block鎖才能進行數據變更操作。但數據頁不在內存時,就需要確保Step 4在Step 3之后執行。因此在緩存purge操作之前,需要根據當前要清理的記錄,找到對應的聚集索引記錄,并檢查相比當前purge線程的readview是否有新版本的聚集索引記錄(即有新的插入操作發生)。
如果檢查到有新的插入,則本次purge操作直接放棄。因為當符合一定條件時,Step 4的操作可以直接把Step1產生的記錄刪除標記清除掉,重用物理空間。
參考函數:`row_purge_poss_sec`:
但是注意上述檢查流程結束時,會在函數`row_purge_poss_sec`中將mtr提交掉,對應的聚集索引頁的Latch會被釋放掉,這意味著可能出現如下序列:
* Step 1: delete-mark X;
* Step 2: delete X,purge線程為其設置watch,并完成在函數`row_purge_poss_sec`中的檢查,準備插入ibuf
* Step 3: insert X,索引頁不在內存,準備插入ibuf
在函數`ibuf_insert`中,針對IBUF_OP_INSERT和IBUF_OP_DELETE_MARK操作,會去檢查是否對應的二級索引頁被設置成sentinel(`buf_page_get_also_watch`),如果是的話,表明當前有一個pending的purge操作,目前的處理邏輯是放棄insert和delete-mark的緩存操作,轉而讀取物理頁。
綜上,如果purge操作先進入`ibuf_insert`,則對應二級索引頁的watch必然被設置,insert操作將放棄緩存,轉而嘗試讀入索引頁;如果insert先進入`ibuf_insert`,則purge操作的緩存放棄。
即使Purge線程完成一系列檢查,進入緩存階段,這時候用戶線程依舊可能會去讀入物理頁;有沒有可能導致purge操作丟失呢 ?答案是否定的!因為purge線程在緩存操作時先將cursor定位到ibuf btree上,對應的ibuf page已將加上latch;而用戶線程如果讀入物理頁,為了merge ibuf entry,也需要請求page latch;當purge線程在拿到latch后,會再檢查一次看看物理頁是否已讀入內存(`buf_pool_watch_occurred`),如果是的話,則放棄本次緩存。
3. 何時清理sentinel
有兩種情況會清理sentinel:
* 第一種情況是purge操作完成緩存后(或者判斷無法進行purge緩存)進行清理;
* 第二種情況是從磁盤讀入文件塊的時候,會調用`buf_page_init_for_read->buf_page_init`初始化一個page對象。這時候會做一個判斷,如果將被讀入的page被設置為sentinel(在watch數組中被設置),則調用`buf_pool_watch_remove`將其從page hash中移除,對應`bp->watch`的數據元素被重置成空閑狀態。
## ibuf merge
有以下幾種場景會觸發ibuf merge操作:
1. 用戶線程選擇二級索引進行數據查詢,這時候必須要讀入二級索引頁,相應的ibuf entry需要merge到Page中。
2. 當嘗試緩存插入操作時,如果預估page的空間不足,可能導致索引分裂,則定位到嘗試緩存的page no在ibuf btree中的位置,最多merge 8個(IBUF_MERGE_AREA) page,merge方式為異步,即發起異步讀索引頁請求。
參考函數:`ibuf_insert_low —> ibuf_get_merge_page_nos_func`
3. 若當前ibuf tree size 超過ibuf->max_size + 10(`IBUF_CONTRACT_DO_NOT_INSERT`)時,執行一次同步的ibuf merge(`ibuf_contract`),merge的page no為隨機定位的cursor,最多一次merge 8個page,同時放棄本次緩存。
其中`ibuf->max_size`默認為25% * buffer pool size,百分比由參數`innodb_change_buffer_max_size`控制,可動態調整。
參考函數:`ibuf_insert_low —> ibuf_contract`
4. 若本次插入ibuf操作可能產生ibuf btree索引分裂(BTR_MODIFY_TREE)時:
* 當前ibuf->size max_size, 不做處理;
* 當前ibuf->size >= ibuf->max_size + 5 (IBUF_CONTRACT_ON_INSERT_SYNC)時,執行一次同步ibuf merge,位置隨機;
* 當前Ibuf->size介于ibuf->max_size 和ibuf->max_size +5 之間時。執行一次異步ibuf merge,位置隨機。
參考函數:`ibuf_insert_low —> ibuf_contract_after_insert`
5. 后臺master線程發起merge
master線程有三種工作狀態:
IDLE:實例處于空閑狀態,以100%的io capacity來作merge操作:
~~~
n_pages = PCT_IO(100);
~~~
相當于一次merge的page數等于innodb_io_capacity
參考函數:`srv_master_do_idle_tasks`
ACTIVE:實例處于活躍狀態,這時候會以如下算法計算需要merge的page數:
~~~
/* By default we do a batch of 5% of the io_capacity */
n_pages = PCT_IO(5);
mutex_enter(&ibuf_mutex);
/* If the ibuf->size is more than half the max_size
then we make more agreesive contraction.
+1 is to avoid division by zero. */
if (ibuf->size > ibuf->max_size / 2) {
ulint diff = ibuf->size - ibuf->max_size / 2;
n_pages += PCT_IO((diff * 100)
/ (ibuf->max_size + 1));
}
mutex_exit(&ibuf_mutex);
~~~
可見在系統active時,會以比較溫和的方式去做merge,如果當前ibuf btree size超過最大值的一半,則嘗試多做一些merge操作。
參考函數:?`srv_master_do_active_tasks`
SHUTDOWN:當執行slow shutdown時,會強制做一次全部的ibuf merge
參考函數:`srv_master_do_shutdown_tasks`
6. 對某個表執行flush table 操作時,會觸發對該表的強制ibuf merge,例如執行:
~~~
flush table tbname for export;
flush table tbname with read lock;
~~~
實際上強制ibuf merge主要是為flush for export準備的,當執行該命令后,為了保證能安全的將ibd拷貝到其他實例上, 需要對該表應用全部的ibuf 緩存。
參考函數:`row_quiesce_table_start`
## “著名” bug
在change buffer的應用史上,最著名的bug要屬?[bug#61104](https://bugs.mysql.com/bug.php?id=61104),其現象為當實例意外crash后,無法從崩潰中恢復,錯誤日志中報如下斷言:
~~~
InnoDB: Failing assertion: page_get_n_recs(page) > 1
~~~
最初官方花了很長的時間都沒有找到這個問題的root cause,只能加了一些代碼邏輯避免不斷crash重啟,讓用戶有機會登錄實例,重建二級索引。
后來Percona的開發人員Alexey Kopytov在[bug#66819](https://bugs.mysql.com/bug.php?id=66819)?提出了該問題的根本原因,指出ibuf entry的刪除和merge 并不是一個原子的操作(即處于兩個mtr事務中),當merge ibuf的mtr提交后crash,就可能在重啟時重復做ibuf merge。如果上次執行DELETE操作導致對應索引頁上記錄數只剩下一條,第二次apply時認為本次操作會產生空頁,從而導致斷言錯誤。
官方很快根據Alexey的意見做了修復,修復方式也比較簡單:
1. 在第一個mtr里,merge ibuf entry 到二級索引頁,并標記刪除ibuf entry,提交mtr;
2. 在第二個mtr里,執行真正的悲觀刪除ibuf entry;
3. 在執行merge操作前,對于被delete mark的ibuf entry,不做merge操作。
具體的參考函數:`ibuf_merge_or_delete_for_page`?和?`ibuf_delete_rec`。
比較烏龍的是,我們發現第一次修復并沒有處理purge線程產生的delete緩存;我們將該發現公布到社區,很快得到了響應,并由上游快速fix掉了,因此完整的補丁分布在兩個版本中:
[官方第一次fix(MySQL5.5.29)](http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/3979)
[官方第二次fix(MySQL5.5.31)](http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/4177)
- 數據庫內核月報目錄
- 數據庫內核月報 - 2016/09
- MySQL · 社區貢獻 · AliSQL那些事兒
- PetaData · 架構體系 · PetaData第二代低成本存儲體系
- MySQL · 社區動態 · MariaDB 10.2 前瞻
- MySQL · 特性分析 · 執行計劃緩存設計與實現
- PgSQL · 最佳實踐 · pg_rman源碼淺析與使用
- MySQL · 捉蟲狀態 · bug分析兩例
- PgSQL · 源碼分析 · PG優化器淺析
- MongoDB · 特性分析· Sharding原理與應用
- PgSQL · 源碼分析 · PG中的無鎖算法和原子操作應用一則
- SQLServer · 最佳實踐 · TEMPDB的設計
- 數據庫內核月報 - 2016/08
- MySQL · 特性分析 ·MySQL 5.7新特性系列四
- PgSQL · PostgreSQL 邏輯流復制技術的秘密
- MySQL · 特性分析 · MyRocks簡介
- GPDB · 特性分析· Greenplum 備份架構
- SQLServer · 最佳實踐 · RDS for SQLServer 2012權限限制提升與改善
- TokuDB · 引擎特性 · REPLACE 語句優化
- MySQL · 專家投稿 · InnoDB物理行中null值的存儲的推斷與驗證
- PgSQL · 實戰經驗 · 旋轉門壓縮算法在PostgreSQL中的實現
- MySQL · 源碼分析 · Query Cache并發處理
- PgSQL · 源碼分析· pg_dump分析
- 數據庫內核月報 - 2016/07
- MySQL · 特性分析 ·MySQL 5.7新特性系列三
- MySQL · 特性分析 · 5.7 代價模型淺析
- PgSQL · 實戰經驗 · 分組TOP性能提升44倍
- MySQL · 源碼分析 · 網絡通信模塊淺析
- MongoDB · 特性分析 · 索引原理
- SQLServer · 特性分析 · XML與JSON應用比較
- MySQL · 最佳實戰 · 審計日志實用案例分析
- MySQL · 性能優化 · 條件下推到物化表
- MySQL · 源碼分析 · Query Cache內部剖析
- MySQL · 捉蟲動態 · 備庫1206錯誤問題說明
- 數據庫內核月報 - 2016/06
- MySQL · 特性分析 · innodb 鎖分裂繼承與遷移
- MySQL · 特性分析 ·MySQL 5.7新特性系列二
- PgSQL · 實戰經驗 · 如何預測Freeze IO風暴
- GPDB · 特性分析· Filespace和Tablespace
- MariaDB · 新特性 · 窗口函數
- MySQL · TokuDB · checkpoint過程
- MySQL · 特性分析 · 內部臨時表
- MySQL · 最佳實踐 · 空間優化
- SQLServer · 最佳實踐 · 數據庫實現大容量插入的幾種方式
- 數據庫內核月報 - 2016/05
- MySQL · 引擎特性 · 基于InnoDB的物理復制實現
- MySQL · 特性分析 · MySQL 5.7新特性系列一
- PostgreSQL · 特性分析 · 邏輯結構和權限體系
- MySQL · 特性分析 · innodb buffer pool相關特性
- PG&GP · 特性分析 · 外部數據導入接口實現分析
- SQLServer · 最佳實踐 · 透明數據加密在SQLServer的應用
- MySQL · TokuDB · 日志子系統和崩潰恢復過程
- MongoDB · 特性分析 · Sharded cluster架構原理
- PostgreSQL · 特性分析 · 統計信息計算方法
- MySQL · 捉蟲動態 · left-join多表導致crash
- 數據庫內核月報 - 2016/04
- MySQL · 參數故事 · innodb_additional_mem_pool_size
- GPDB · 特性分析 · Segment事務一致性與異常處理
- GPDB · 特性分析 · Segment 修復指南
- MySQL · 捉蟲動態 · 并行復制外鍵約束問題二
- PgSQL · 性能優化 · 如何瀟灑的處理每天上百TB的數據增量
- Memcached · 最佳實踐 · 熱點 Key 問題解決方案
- MongoDB · 最佳實踐 · 短連接Auth性能優化
- MySQL · 最佳實踐 · RDS 只讀實例延遲分析
- MySQL · TokuDB · TokuDB索引結構--Fractal Tree
- MySQL · TokuDB · Savepoint漫談
- 數據庫內核月報 - 2016/03
- MySQL · TokuDB · 事務子系統和 MVCC 實現
- MongoDB · 特性分析 · MMAPv1 存儲引擎原理
- PgSQL · 源碼分析 · 優化器邏輯推理
- SQLServer · BUG分析 · Agent 鏈接泄露分析
- Redis · 特性分析 · AOF Rewrite 分析
- MySQL · BUG分析 · Rename table 死鎖分析
- MySQL · 物理備份 · Percona XtraBackup 備份原理
- GPDB · 特性分析· GreenPlum FTS 機制
- MySQL · 答疑解惑 · 備庫Seconds_Behind_Master計算
- MySQL · 答疑解惑 · MySQL 鎖問題最佳實踐
- 數據庫內核月報 - 2016/02
- MySQL · 引擎特性 · InnoDB 文件系統之文件物理結構
- MySQL · 引擎特性 · InnoDB 文件系統之IO系統和內存管理
- MySQL · 特性分析 · InnoDB transaction history
- PgSQL · 會議見聞 · PgConf.Russia 2016 大會總結
- PgSQL · 答疑解惑 · PostgreSQL 9.6 并行查詢實現分析
- MySQL · TokuDB · TokuDB之黑科技工具
- PgSQL · 性能優化 · PostgreSQL TPC-C極限優化玩法
- MariaDB · 版本特性 · MariaDB 的 GTID 介紹
- MySQL · 特性分析 · 線程池
- MySQL · 答疑解惑 · mysqldump tips 兩則
- 數據庫內核月報 - 2016/01
- MySQL · 引擎特性 · InnoDB 事務鎖系統簡介
- GPDB · 特性分析· GreenPlum Primary/Mirror 同步機制
- MySQL · 專家投稿 · MySQL5.7 的 JSON 實現
- MySQL · 特性分析 · 優化器 MRR & BKA
- MySQL · 答疑解惑 · 物理備份死鎖分析
- MySQL · TokuDB · Cachetable 的工作線程和線程池
- MySQL · 特性分析 · drop table的優化
- MySQL · 答疑解惑 · GTID不一致分析
- PgSQL · 特性分析 · Plan Hint
- MariaDB · 社區動態 · MariaDB on Power8 (下)
- 數據庫內核月報 - 2015/12
- MySQL · 引擎特性 · InnoDB 事務子系統介紹
- PgSQL · 特性介紹 · 全文搜索介紹
- MongoDB · 捉蟲動態 · Kill Hang問題排查記錄
- MySQL · 參數優化 ·RDS MySQL參數調優最佳實踐
- PgSQL · 特性分析 · 備庫激活過程分析
- MySQL · TokuDB · 讓Hot Backup更完美
- PgSQL · 答疑解惑 · 表膨脹
- MySQL · 特性分析 · Index Condition Pushdown (ICP)
- MariaDB · 社區動態 · MariaDB on Power8
- MySQL · 特性分析 · 企業版特性一覽
- 數據庫內核月報 - 2015/11
- MySQL · 社區見聞 · OOW 2015 總結 MySQL 篇
- MySQL · 特性分析 · Statement Digest
- PgSQL · 答疑解惑 · PostgreSQL 用戶組權限管理
- MySQL · 特性分析 · MDL 實現分析
- PgSQL · 特性分析 · full page write 機制
- MySQL · 捉蟲動態 · MySQL 外鍵異常分析
- MySQL · 答疑解惑 · MySQL 優化器 range 的代價計算
- MySQL · 捉蟲動態 · ORDER/GROUP BY 導致 mysqld crash
- MySQL · TokuDB · TokuDB 中的行鎖
- MySQL · 捉蟲動態 · order by limit 造成優化器選擇索引錯誤
- 數據庫內核月報 - 2015/10
- MySQL · 引擎特性 · InnoDB 全文索引簡介
- MySQL · 特性分析 · 跟蹤Metadata lock
- MySQL · 答疑解惑 · 索引過濾性太差引起CPU飆高分析
- PgSQL · 特性分析 · PG主備流復制機制
- MySQL · 捉蟲動態 · start slave crash 診斷分析
- MySQL · 捉蟲動態 · 刪除索引導致表無法打開
- PgSQL · 特性分析 · PostgreSQL Aurora方案與DEMO
- TokuDB · 捉蟲動態 · CREATE DATABASE 導致crash問題
- PgSQL · 特性分析 · pg_receivexlog工具解析
- MySQL · 特性分析 · MySQL權限存儲與管理
- 數據庫內核月報 - 2015/09
- MySQL · 引擎特性 · InnoDB Adaptive hash index介紹
- PgSQL · 特性分析 · clog異步提交一致性、原子操作與fsync
- MySQL · 捉蟲動態 · BUG 幾例
- PgSQL · 答疑解惑 · 詭異的函數返回值
- MySQL · 捉蟲動態 · 建表過程中crash造成重建表失敗
- PgSQL · 特性分析 · 談談checkpoint的調度
- MySQL · 特性分析 · 5.6 并行復制恢復實現
- MySQL · 備庫優化 · relay fetch 備庫優化
- MySQL · 特性分析 · 5.6并行復制事件分發機制
- MySQL · TokuDB · 文件目錄談
- 數據庫內核月報 - 2015/08
- MySQL · 社區動態 · InnoDB Page Compression
- PgSQL · 答疑解惑 · RDS中的PostgreSQL備庫延遲原因分析
- MySQL · 社區動態 · MySQL5.6.26 Release Note解讀
- PgSQL · 捉蟲動態 · 執行大SQL語句提示無效的內存申請大小
- MySQL · 社區動態 · MariaDB InnoDB表空間碎片整理
- PgSQL · 答疑解惑 · 歸檔進程cp命令的core文件追查
- MySQL · 答疑解惑 · open file limits
- MySQL · TokuDB · 瘋狂的 filenum++
- MySQL · 功能分析 · 5.6 并行復制實現分析
- MySQL · 功能分析 · MySQL表定義緩存
- 數據庫內核月報 - 2015/07
- MySQL · 引擎特性 · Innodb change buffer介紹
- MySQL · TokuDB · TokuDB Checkpoint機制
- PgSQL · 特性分析 · 時間線解析
- PgSQL · 功能分析 · PostGIS 在 O2O應用中的優勢
- MySQL · 引擎特性 · InnoDB index lock前世今生
- MySQL · 社區動態 · MySQL內存分配支持NUMA
- MySQL · 答疑解惑 · 外鍵刪除bug分析
- MySQL · 引擎特性 · MySQL logical read-ahead
- MySQL · 功能介紹 · binlog拉取速度的控制
- MySQL · 答疑解惑 · 浮點型的顯示問題
- 數據庫內核月報 - 2015/06
- MySQL · 引擎特性 · InnoDB 崩潰恢復過程
- MySQL · 捉蟲動態 · 唯一鍵約束失效
- MySQL · 捉蟲動態 · ALTER IGNORE TABLE導致主備不一致
- MySQL · 答疑解惑 · MySQL Sort 分頁
- MySQL · 答疑解惑 · binlog event 中的 error code
- PgSQL · 功能分析 · Listen/Notify 功能
- MySQL · 捉蟲動態 · 任性的 normal shutdown
- PgSQL · 追根究底 · WAL日志空間的意外增長
- MySQL · 社區動態 · MariaDB Role 體系
- MySQL · TokuDB · TokuDB數據文件大小計算
- 數據庫內核月報 - 2015/05
- MySQL · 引擎特性 · InnoDB redo log漫游
- MySQL · 專家投稿 · MySQL數據庫SYS CPU高的可能性分析
- MySQL · 捉蟲動態 · 5.6 與 5.5 InnoDB 不兼容導致 crash
- MySQL · 答疑解惑 · InnoDB 預讀 VS Oracle 多塊讀
- PgSQL · 社區動態 · 9.5 新功能BRIN索引
- MySQL · 捉蟲動態 · MySQL DDL BUG
- MySQL · 答疑解惑 · set names 都做了什么
- MySQL · 捉蟲動態 · 臨時表操作導致主備不一致
- TokuDB · 引擎特性 · zstd壓縮算法
- MySQL · 答疑解惑 · binlog 位點刷新策略
- 數據庫內核月報 - 2015/04
- MySQL · 引擎特性 · InnoDB undo log 漫游
- TokuDB · 產品新聞 · RDS TokuDB小手冊
- PgSQL · 社區動態 · 說一說PgSQL 9.4.1中的那些安全補丁
- MySQL · 捉蟲動態 · 連接斷開導致XA事務丟失
- MySQL · 捉蟲動態 · GTID下slave_net_timeout值太小問題
- MySQL · 捉蟲動態 · Relay log 中 GTID group 完整性檢測
- MySQL · 答疑釋惑 · UPDATE交換列單表和多表的區別
- MySQL · 捉蟲動態 · 刪被引用索引導致crash
- MySQL · 答疑釋惑 · GTID下auto_position=0時數據不一致
- 數據庫內核月報 - 2015/03
- MySQL · 答疑釋惑· 并發Replace into導致的死鎖分析
- MySQL · 性能優化· 5.7.6 InnoDB page flush 優化
- MySQL · 捉蟲動態· pid file丟失問題分析
- MySQL · 答疑釋惑· using filesort VS using temporary
- MySQL · 優化限制· MySQL index_condition_pushdown
- MySQL · 捉蟲動態·DROP DATABASE外鍵約束的GTID BUG
- MySQL · 答疑釋惑· lower_case_table_names 使用問題
- PgSQL · 特性分析· Logical Decoding探索
- PgSQL · 特性分析· jsonb類型解析
- TokuDB ·引擎機制· TokuDB線程池
- 數據庫內核月報 - 2015/02
- MySQL · 性能優化· InnoDB buffer pool flush策略漫談
- MySQL · 社區動態· 5.6.23 InnoDB相關Bugfix
- PgSQL · 特性分析· Replication Slot
- PgSQL · 特性分析· pg_prewarm
- MySQL · 答疑釋惑· InnoDB丟失自增值
- MySQL · 答疑釋惑· 5.5 和 5.6 時間類型兼容問題
- MySQL · 捉蟲動態· 變量修改導致binlog錯誤
- MariaDB · 特性分析· 表/表空間加密
- MariaDB · 特性分析· Per-query variables
- TokuDB · 特性分析· 日志詳解
- 數據庫內核月報 - 2015/01
- MySQL · 性能優化· Group Commit優化
- MySQL · 新增特性· DDL fast fail
- MySQL · 性能優化· 啟用GTID場景的性能問題及優化
- MySQL · 捉蟲動態· InnoDB自增列重復值問題
- MySQL · 優化改進· 復制性能改進過程
- MySQL · 談古論今· key分區算法演變分析
- MySQL · 捉蟲動態· mysql client crash一例
- MySQL · 捉蟲動態· 設置 gtid_purged 破壞AUTO_POSITION復制協議
- MySQL · 捉蟲動態· replicate filter 和 GTID 一起使用的問題
- TokuDB·特性分析· Optimize Table
- 數據庫內核月報 - 2014/12
- MySQL· 性能優化·5.7 Innodb事務系統
- MySQL· 踩過的坑·5.6 GTID 和存儲引擎那會事
- MySQL· 性能優化·thread pool 原理分析
- MySQL· 性能優化·并行復制外建約束問題
- MySQL· 答疑釋惑·binlog event有序性
- MySQL· 答疑釋惑·server_id為0的Rotate
- MySQL· 性能優化·Bulk Load for CREATE INDEX
- MySQL· 捉蟲動態·Opened tables block read only
- MySQL· 優化改進· GTID啟動優化
- TokuDB· Binary Log Group Commit with TokuDB
- 數據庫內核月報 - 2014/11
- MySQL· 捉蟲動態·OPTIMIZE 不存在的表
- MySQL· 捉蟲動態·SIGHUP 導致 binlog 寫錯
- MySQL· 5.7改進·Recovery改進
- MySQL· 5.7特性·高可用支持
- MySQL· 5.7優化·Metadata Lock子系統的優化
- MySQL· 5.7特性·在線Truncate undo log 表空間
- MySQL· 性能優化·hash_scan 算法的實現解析
- TokuDB· 版本優化· 7.5.0
- TokuDB· 引擎特性· FAST UPDATES
- MariaDB· 性能優化·filesort with small LIMIT optimization
- 數據庫內核月報 - 2014/10
- MySQL· 5.7重構·Optimizer Cost Model
- MySQL· 系統限制·text字段數
- MySQL· 捉蟲動態·binlog重放失敗
- MySQL· 捉蟲動態·從庫OOM
- MySQL· 捉蟲動態·崩潰恢復失敗
- MySQL· 功能改進·InnoDB Warmup特性
- MySQL· 文件結構·告別frm文件
- MariaDB· 新鮮特性·ANALYZE statement 語法
- TokuDB· 主備復制·Read Free Replication
- TokuDB· 引擎特性·壓縮
- 數據庫內核月報 - 2014/09
- MySQL· 捉蟲動態·GTID 和 DELAYED
- MySQL· 限制改進·GTID和升級
- MySQL· 捉蟲動態·GTID 和 binlog_checksum
- MySQL· 引擎差異·create_time in status
- MySQL· 參數故事·thread_concurrency
- MySQL· 捉蟲動態·auto_increment
- MariaDB· 性能優化·Extended Keys
- MariaDB·主備復制·CREATE OR REPLACE
- TokuDB· 參數故事·數據安全和性能
- TokuDB· HA方案·TokuDB熱備
- 數據庫內核月報 - 2014/08
- MySQL· 參數故事·timed_mutexes
- MySQL· 參數故事·innodb_flush_log_at_trx_commit
- MySQL· 捉蟲動態·Count(Distinct) ERROR
- MySQL· 捉蟲動態·mysqldump BUFFER OVERFLOW
- MySQL· 捉蟲動態·long semaphore waits
- MariaDB·分支特性·支持大于16K的InnoDB Page Size
- MariaDB·分支特性·FusionIO特性支持
- TokuDB· 性能優化·Bulk Fetch
- TokuDB· 數據結構·Fractal-Trees與LSM-Trees對比
- TokuDB·社區八卦·TokuDB團隊