## 前言
我們知道InnoDB的索引組織結構為Btree。通常情況下,我們需要根據查詢條件,從根節點開始尋路到葉子節點,找到滿足條件的記錄。為了減少尋路開銷,InnoDB本身做了幾點優化。
首先,對于連續記錄掃描,InnoDB在滿足比較嚴格的條件時采用row cache的方式連續讀取8條記錄(并將記錄格式轉換成MySQL Format),存儲在線程私有的`row_prebuilt_t::fetch_cache`中;這樣一次尋路就可以獲取多條記錄,在server層處理完一條記錄后,可以直接從cache中取數據而無需再次尋路,直到cache中數據取完,再進行下一輪。
另一種方式是,當一次進入InnoDB層獲得數據后,在返回server層前,當前在btree上的cursor會被暫時存儲到`row_prebuilt_t::pcur`中,當再次返回InnoDB層撈數據時,如果對應的Block沒有發生任何修改,則可以繼續沿用之前存儲的cursor,無需重新定位。
上面這兩種方式都是為了減少了重新尋路的次數,而對于一次尋路的開銷,則使用Adaptive hash index來解決。AHI是一個內存結構,嚴格來說不是傳統意義上的索引,可以把它理解為建立在Btree索引上的“索引”。
本文代碼分析基于MySQL 5.7.7-rc,描述的邏輯適用于5.7.7之前及5.6版本。但在即將發布的MySQL-5.7.8版本中, InnoDB根據索引id對AHI進行了分區處理,以此來降低btr_search_latch讀寫鎖競爭,由于尚未發布,本文暫不覆蓋相關內容。
我們以一個干凈啟動的實例作為起點,分析下如何進行AHI構建的過程。
## 初始化
AHI在內存中表現就是一個普通的哈希表對象,存儲在`btr_search_sys_t::hash_index`中,對AHI的查刪改操作都是通過一個全局讀寫鎖`btr_search_latch`來保護。
在實例啟動,完成buffer pool初始化后,會初始化AHI子系統相關對象,并分配AHI內存,大小為buffer pool的1/64。
參考函數:`btr_search_sys_create`
Tips:MySQL 5.7已經開始支持InnoDB buffer pool的動態調整,其策略是buffer pool的大小改變超過1倍,就重新分配AHI Hash內存(`btr_search_sys_resize`)。
## 觸發AHI信息統計
在系統剛啟動時,索引對象上沒有足夠的信息來啟發是否適合進行AHI緩存,因此開始有個信息搜集的階段,在索引對象上維護了`dict_index_t::search_info`,類型為`btr_search_t`,用于跟蹤當前索引使用AHI的關鍵信息。
在第一次執行SQL時,需要從btree的root節點開始,當尋址到匹配的葉子節點時,會走如下邏輯:
btr_cur_search_to_nth_level:
~~~
if (btr_search_enabled && !index->disable_ahi) {
btr_search_info_update(index, cursor);
}
~~~
這里會判斷臟讀AHI開關(btr_search_enabled)是否打開,以及`index->diable_ahi`是否為false。第二個條件是MySQL5.7對臨時表的優化,避免臨時表操作對全局對象的影響,針對臨時表不做AHI構建。
我們看看函數btr_search_info_update的邏輯:
1. 對`info->hash_analysis++`,當`info->hash_analysis`值超過`BTR_SEARCH_HASH_ANALYSIS`(17)時,也就是說對該索引尋路到葉子節點17次后,才會去做AHI分析(進入步驟2)
2. 進入函數`btr_search_info_update_slow`
在連續執行17次對相同索引的操作后,滿足`info->hash_analysis`大于等于`BTR_SEARCH_HASH_ANALYSIS`的條件,就會調用函數`btr_search_info_update_slow`來更新search_info,這主要是為了避免頻繁的索引查詢分析產生的過多CPU開銷。
InnoDB通過索引條件構建一個可用于查詢的tuple,而AHI需要根據tuple定位到葉子節點上記錄的位置,既然AHI是構建在Btree索引上的索引,它的鍵值就是通過索引的前N列的值計算的來,所有的信息搜集統計都是為了確定一個合適的”N” ,這個值也是個動態的值,會跟隨應用的負載自適應調整并觸發block上的AHI重構建。
`btr_search_info_update_slow`包含三個部分:更新索引查詢信息、block上的查詢信息以及為當前block構建AHI,下面幾小節分別介紹。
## 更新索引上的查詢信息
參考函數:`btr_search_info_update_hash`
這里涉及到的幾個search_info變量包括:
`btr_search_t::n_hash_potential`?表示如果使用AHI構建索引,潛在的可能成功的次數;
`btr_search_t::hash_analysis`?若設置了新的建議前綴索引模式,則重置為0,隨后的17次查詢分析可以忽略更新search_info。
下面兩個字段表示推薦的前綴索引模式:
`btr_search_t::n_fields`?推薦構建AHI的索引列數;
`btr_search_t::left_side`?表示是否在相同索引前綴的最左索引記錄構建AHI;值為true時,則對于相同前綴索引的記錄,只存儲最右的那個記錄。
通過n_fields和left_side可以指導選擇哪些列作為索引前綴來構建(fold, rec)哈希記錄。如果用戶的SQL的索引前綴列的個數大于等于構建AHI時的前綴索引,就可以用上AHI。
Tip1:在5.7之前的版本中,還支持索引中的字符串前綴作為構建AHI的鍵值的一部分,但上游認為帶來的好處并不明顯,因此將`btr_search_t::n_bytes`?移除了(參見commit?[6f5f19b338543277a108a97710de8dd59b9dbb60](https://github.com/mysql/mysql-server/commit/6f5f19b338543277a108a97710de8dd59b9dbb60 "Bug#16852278 SIMPLIFY RECORD COMPARISONS"),?[42499d9394bf103a27d63cd38b0c3c6bd738a7c7](https://github.com/mysql/mysql-server/commit/42499d9394bf103a27d63cd38b0c3c6bd738a7c7 "Remove support for byte-level prefix granularity in searches."))。
Tip2:然而上游在測試中發現,如果把n_bytes移除,可能在諸如順序插入這樣的場景存在性能退化(參閱commit?[00ec81a9efc1108376813f15935b52c451a268cf](https://github.com/mysql/mysql-server/commit/00ec81a9efc1108376813f15935b52c451a268cf "Bug#21198396 REINTRODUCE ADAPTIVE HASH INDEX FIELD PREFIXES")),因此在新發布的MySQL5.7.8版本中又重新引入,本文分析代碼時統一基于MySQL5.7.7版本。
兩種情況需要構建建議的前綴索引列:
1. 當前是第一次為該索引做AHI分析,`btr_search_t::n_hash_potential`值為0,需要構建建議的前綴索引列;
2. 新的記錄匹配模式發生了變化`(info->left_side == (info->n_fields <=cursor->low_match))`,需要重新設置前綴索引列。
相關代碼段:
~~~
if (cursor->up_match == cursor->low_match) {
info->n_hash_potential = 0;
/* For extra safety, we set some sensible values here */
info->n_fields = 1;
info->left_side = TRUE;
} else if (cursor->up_match > cursor->low_match) {
info->n_hash_potential = 1;
if (cursor->up_match >= n_unique) {
info->n_fields = n_unique;
} else if (cursor->low_match < cursor->up_match) {
info->n_fields = cursor->low_match + 1;
} else {
info->n_fields = cursor->low_match;
}
info->left_side = TRUE;
} else {
info->n_hash_potential = 1;
if (cursor->low_match >= n_unique) {
info->n_fields = n_unique;
} else if (cursor->low_match > cursor->up_match) {
info->n_fields = cursor->up_match + 1;
} else {
info->n_fields = cursor->up_match;
}
info->left_side = FALSE;
}
~~~
從上述代碼可以看到,在low_match和up_match之間,選擇小一點match的索引列數的來進行設置,但不超過唯一確定索引記錄值的列的個數:
1. 當low_match小于up_match時,left_side設置為true,表示相同前綴索引的記錄只緩存最左記錄;
2. 當low_match大于up_match時,left_side設置為false,表示相同前綴索引的記錄只緩存最右記錄。
如果不是第一次進入seach_info分析,有兩種情況會遞增`btr_search_t::n_hash_potential`:
* 本次查詢的up_match和當前推薦的前綴索引都能唯一決定一條索引記錄(例如唯一索引),則根據search_info推薦的前綴索引列構建AHI肯定能命中,遞增?`info->n_hash_potential`;
~~~
if (info->n_fields >= n_unique && cursor->up_match >= n_unique) {
increment_potential:
info->n_hash_potential++;
return;
}
~~~
* 本次查詢的tuple可以通過建議的前綴索引列構建的AHI定位到。
~~~
if (info->left_side == (info->n_fields <= cursor->up_match)) {
goto increment_potential;
}
~~~
很顯然,如果對同一個索引的查詢交替使用不同的查詢模式,可能上次更新的search_info很快就會被重新設置,具有固定模式的索引查詢將會受益于AHI索引。
## 更新block上的查詢信息
參考函數:`btr_search_update_block_hash_info`
更新數據頁block上的查詢信息,涉及到修改的變量包括:
`btr_search_info::last_hash_succ`?最近一次成功(或可能成功)使用AHI;
`buf_block_t::n_hash_helps`?計數值,如果使用當前推薦的前綴索引列構建AHI可能命中的次數,用于啟發構建/重新構建數據頁上的AHI記錄項;
`buf_block_t::n_fields`?推薦在block上構建AHI的前綴索引列數;
`buf_block_t::left_side`?和search_info上對應字段含義相同。
函數主要流程包括:
1. 首先設置`btr_search_info::last_hash_succ`?為FALSE
這會導致在分析過程中無法使用AHI進行檢索,感覺這里的設置不是很合理。這意味著每次分析一個新的block,都會導致AHI短暫不可用。
2. 初始化或更新block上的查詢信息
~~~
if ((block->n_hash_helps > 0)
&& (info->n_hash_potential > 0)
&& (block->n_fields == info->n_fields)
&& (block->left_side == info->left_side)) {
if ((block->index)
&& (block->curr_n_fields == info->n_fields)
&& (block->curr_left_side == info->left_side)) {
/* The search would presumably have succeeded using
the hash index */
info->last_hash_succ = TRUE;
}
block->n_hash_helps++;
} else {
block->n_hash_helps = 1;
block->n_fields = info->n_fields;
block->left_side = info->left_side;
}
~~~
當block第一次被touch到并進入該函數時,設置block上的建議索引列值;以后再進入時,如果和索引上的全局search_info相匹配,則遞增`block->n_hash_helps`,啟發后續的創建或重構建AHI。
如果當前數據頁block上已經構建了AHI記錄項,且`buf_block_t::curr_n_fields`等字段和`btr_search_info`上對應字段值相同時,則認為當前SQL如果使用AHI索引能夠命中,因此將`btr_search_info::last_hash_succ`設置為true,下次再使用相同索引檢索btree時就會嘗試使用AHI。
3. 在初始化或更新block上的變量后,需要判斷是否為整個page構建AHI索引:
~~~
if ((block->n_hash_helps > page_get_n_recs(block->frame)
/ BTR_SEARCH_PAGE_BUILD_LIMIT)
&& (info->n_hash_potential >= BTR_SEARCH_BUILD_LIMIT)) {
if ((!block->index)
|| (block->n_hash_helps
> 2 * page_get_n_recs(block->frame))
|| (block->n_fields != block->curr_n_fields)
|| (block->left_side != block->curr_left_side)) {
/* Build a new hash index on the page */
return(TRUE);
}
}
~~~
簡單來說,當滿足下面三個條件時,就會去為整個block上構建AHI記錄項:
* 分析使用AHI可以成功查詢的次數(`buf_block_t::n_hash_helps`)超過block上記錄數的16(`BTR_SEARCH_PAGE_BUILD_LIMIT`)分之一;
* `btr_search_info::n_hash_potential`大于等于`BTR_SEARCH_BUILD_LIMIT`?(100),表示連續100次潛在的成功使用AHI可能性;
* 尚未為當前block構造過索引、或者當前block上已經構建了AHI索引且`block->n_hash_helps`大于page上記錄數的兩倍、或者當前block上推薦的前綴索引列發生了變化 。
## 為數據頁構建AHI索引
如果在上一階段判斷認為可以為當前page構建AHI索引(函數`btr_search_update_block_hash_info`返回值為TRUE),則根據當前推薦的索引前綴進行AHI構建。
參考函數:`btr_search_build_page_hash_index`
分為三個階段:
1. 檢查階段:加btr_search_latch的S鎖,判斷AHI開關是否打開;如果block上已經構建了老的AHI但前綴索引列和當前推薦的不同,則清空Block對應的AHI記錄項(`btr_search_drop_page_hash_index`);檢查n_fields和page上的記錄數;然后釋放btr_search_latch的S鎖;
2. 搜集階段:根據推薦的索引列數計算記錄fold值,將對應的數據頁記錄內存地址到數組里;
根據left_mode值,相同的前綴索引列值會有不同的行為,舉個簡單的例子,假設page上記錄為 (2,1), (2,2), (5, 3), (5, 4), (7, 5), (8, 6),n_fields=1
* 若left_most為true,則hash存儲的記錄為(2,1) , (5, 3), (7, 5), (8,6)
* 若left_most為false,則hash存儲的記錄為(2, 2), (5, 4), (7,5), (8, 6)
3. 插入階段:加btr_search_latch的X鎖,將第二階段搜集的(fold, rec)插入到AHI中,并更新:
~~~
if (!block->index) {
index->search_info->ref_count++;
}
block->n_hash_helps = 0;
block->curr_n_fields = n_fields;
block->curr_left_side = left_side;
block->index = index;
~~~
PS:由于第二階段釋放了btr_search_latch鎖,這里還得判斷block上的AHI信息是否發生了變化,如果block上已經構建了AHI且block->curr_*幾個變量和當前嘗試構建的檢索模式不同,則放棄本次構建。
## 使用AHI
AHI的目的是根據用戶提供的查詢條件加速定位到葉子節點,一般如果有固定的查詢pattern,都可以通過AHI受益,尤其是Btree高度比較大的時候。
入口函數:`btr_cur_search_to_nth_level`
相關代碼:
~~~
/* Use of AHI is disabled for intrinsic table as these tables re-use
the index-id and AHI validation is based on index-id. */
if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_NOT_LOCKED
&& latch_mode <= BTR_MODIFY_LEAF
&& info->last_hash_succ
&& !index->disable_ahi
&& !estimate
# ifdef PAGE_CUR_LE_OR_EXTENDS
&& mode != PAGE_CUR_LE_OR_EXTENDS
# endif /* PAGE_CUR_LE_OR_EXTENDS */
&& !dict_index_is_spatial(index)
/* If !has_search_latch, we do a dirty read of
btr_search_enabled below, and btr_search_guess_on_hash()
will have to check it again. */
&& UNIV_LIKELY(btr_search_enabled)
&& !modify_external
&& btr_search_guess_on_hash(index, info, tuple, mode,
latch_mode, cursor,
has_search_latch, mtr)) {
~~~
從代碼段可以看出,需要滿足如下條件才能夠使用AHI:
* 沒有加btr_search_latch寫鎖。如果加了寫鎖,可能操作時間比較耗時,走AHI檢索記錄就得不償失了;
* latch_mode <= BTR_MODIFY_LEAF,表明本次只是一次不變更BTREE結構的DML或查詢(包括等值、RANGE等查詢)操作;
* `btr_search_info::last_hash_succ`為true表示最近一次使用AHI成功(或可能成功)了;
* 打開AHI開關;
* 查詢優化階段的估值操作,例如計算range范圍等,典型的堆棧包括:`handler::multi_range_read_info_const` –>?`ha_innobase::records_in_range`?–>?`btr_estimate_n_rows_in_range`?–>?`btr_cur_search_to_nth_level`;
* 不是spatial索引;
* 調用者無需分配外部存儲頁(BTR_MODIFY_EXTERNAL,主要用于輔助寫入大的blob數據,參考struct btr_blob_log_check_t)。
當滿足上述條件時,進入函數`btr_search_guess_on_hash`,根據當前的查詢tuple對象計算fold,并查詢AHI;只有當前檢索使用的tuple列的個數大于等于構建AHI的列的個數時,才能夠使用AHI索引。
`btr_search_guess_on_hash`:
* 首先用戶提供的前綴索引查詢條件必須大于等于構建AHI時的前綴索引列數,這里存在一種可能性:索引上的search_info的n_fields 和block上構建AHI時的cur_n_fields值已經不相同了,但是我們并不知道本次查詢到底落在哪個block上,這里一致以search_info上的n_fields為準來計算fold,去查詢AHI;
* 在檢索AHI時需要加&btr_search_latch的S鎖;
* 如果本次無法命中AHI,就會將`btr_search_info::last_hash_succ`設置為false,這意味著隨后的查詢都不會去使用AHI了,只能等待下一路查詢信息分析后才可能再次啟動(`btr_search_failure`);
* 對于從ahi中獲得的記錄指針,還需要根據當前的查詢模式檢查是否是正確的記錄位置(`btr_search_check_guess`)。
如果本次查詢使用了AHI,但查詢失敗了(`cursor->flag == BTR_CUR_HASH_FAIL`),并且當前block構建AHI索引的curr_n_fields等字段和btr_search_info上的相符合,則根據當前cursor定位到的記錄插入AHI。參考函數:`btr_search_update_hash_ref`。
從上述分析可見,AHI如其名,完全是自適應的,如果檢索模式不固定,很容易就出現無法用上AHI或者AHI失效的情況。
## 維護AHI
1. 關閉選項innodb_adaptive_hash_index;
* 持有`dict_sys->mutex`和`btr_search_latch`的X鎖;
* 遍歷`dict_sys->table_LRU`和`dict_sys->table_non_LRU`鏈表,將每個表上的所有索引的`index->search_info->ref_count`設置為0;
* 釋放`dict_sys->mutex`;
* 遍歷buffer pool,將block上的index標記(`buf_block_t::index`)清空為NULL;
* 清空AHI中的哈希項,并釋放為記錄項分配的Heap;
* 釋放btr_search_latch。
參考函數:`btr_search_disable`
2. `index->search_info`的ref_count不為0時,無法從數據集詞典cache中將對應的表驅逐,workaround的方式是臨時關閉AHI開關;
參考函數:`dict_table_can_be_evicted`、`dict_index_remove_from_cache_low`
3. 刪除索引頁上的記錄,或者更新的是二級索引、或者更新了主鍵且影響了排序鍵值,則需要從AHI上將對應的索引記錄刪除;
參考函數:`btr_search_update_hash_on_delete`
4. 插入新的記錄時,如果本次插入未產生頁面重組、操作的page為葉子節點,且本次插入操作使用過AHI定位成功,則先嘗試更新再嘗試插入,否則直接插入對應的AHI記錄項;
參考函數:`btr_search_update_hash_node_on_insert`、`btr_search_update_hash_on_insert`
5. 涉及索引樹分裂或者節點合并,或從LRU中驅逐page(buf_LRU_free_page)時,需要清空AHI對應的page。
參考函數:`btr_search_drop_page_hash_index`
## shortcut查詢模式
在`row_search_mvcc`函數中,首先會去判斷在滿足一定條件時,使用shortcut模式,利用AHI索引來進行檢索。
只有滿足嚴苛的條件時(例如需要唯一鍵查詢、使用聚集索引、長度不超過八分之一的page size、隔離級別在RC及RC之上、活躍的Read view等等條件,具體的參閱代碼),才能使用shortcut:
* 加`btr_search_latch`的S鎖;
* 然后通過`row_sel_try_search_shortcut_for_mysql`檢索記錄;如果找到滿足條件的記錄,本次查詢可以不釋放 btr_search_latch,這意味著InnoDB/server層交互期間可能持有AHI鎖,但最多在10000次(BTR_SEA_TIMEOUT)交互后釋放AHI latch。一旦發現有別的線程在等待AHI X 鎖,也會主動釋放其擁有的S鎖。
然而, Percona的開發Alexey Kopytov認為這種長時間擁有的`btr_search_latch`的方式是沒有必要的,這種設計方式出現在很久之前加鎖、解鎖非常昂貴的時代,然而現在的CPU已經很先進了,完全沒有必要,在Percona的版本中,一次shortcut的查詢操作后都直接釋放掉`btr_search_latch`(參閱[bug#1218347](https://bugs.launchpad.net/percona-server/+bug/1218347))。
## AHI監控項
我們可以通過`information_schema.innodb_metrics`來監控AHI模塊的運行狀態
首先打開監控:
~~~
mysql> set global innodb_monitor_enable = module_adaptive_hash;
Query OK, 0 rows affected (0.00 sec)
mysql> select status, name, subsystem from INNODB_METRICS where subsystem like '%adaptive_hash%';
+---------+------------------------------------------+---------------------+
| status | name | subsystem |
+---------+------------------------------------------+---------------------+
| enabled | adaptive_hash_searches | adaptive_hash_index |
| enabled | adaptive_hash_searches_btree | adaptive_hash_index |
| enabled | adaptive_hash_pages_added | adaptive_hash_index |
| enabled | adaptive_hash_pages_removed | adaptive_hash_index |
| enabled | adaptive_hash_rows_added | adaptive_hash_index |
| enabled | adaptive_hash_rows_removed | adaptive_hash_index |
| enabled | adaptive_hash_rows_deleted_no_hash_entry | adaptive_hash_index |
| enabled | adaptive_hash_rows_updated | adaptive_hash_index |
+---------+------------------------------------------+---------------------+
8 rows in set (0.00 sec)
~~~
重置所有的計數
~~~
mysql> set global innodb_monitor_reset_all = 'adaptive_hash%';
Query OK, 0 rows affected (0.00 sec)
~~~
該表搜集了AHI子系統諸如AHI查詢次數,更新次數等信息,可以很好的監控其運行狀態,在某些負載下,AHI并不適合打開,關閉AHI可以避免額外的維護開銷。當然這取決于你針對具體負載的性能測試。
- 數據庫內核月報目錄
- 數據庫內核月報 - 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團隊