天天看點

MySQL · 引擎特性 · MySQL logical read-ahead

這兩種方式之是以帶來了更高的吞吐量,都基于資料存儲的連續性的假設,比如mysql使用自增字段作為pk的innodb索引表,或者是oracle使用預設的堆表,但當這樣的假設條件不成立的時候,怎麼辦?

考慮下面的一個場景,如下圖所示:

MySQL · 引擎特性 · MySQL logical read-ahead

這是一個b-tree結構,典型的innodb的索引聚簇表,這樣的結構很容易構造,比如使用一個非連續的字段作為索引字段,随機對記錄進行插入,這樣leaf page連結清單上的page_no就會産生非連續性,如果進行一次全表掃描,比如 <code>checksum table t</code>,按照正常的升序掃描,leaf page掃描的page_no順序是3, 4, 5230等等,這樣其實是無法使用到innodb 的linear read-ahead,更沒有辦法合并io請求。

對于存在時間比較長,變更又比較多的大表,除非我們對于這個表進行重建,否則leaf page的離散性會随着時間的推移,越來越嚴重。但對于線上應用來說,重建又會産生比較大的運維風險,這裡就介紹一種平衡的方法,logical read-ahead。

邏輯預讀的概念是指,根據branch節點來預讀leaf節點。

邏輯預讀使用兩個掃描路徑:

1. 一個cursor定位到leaf page,然後根據leaf page之間的雙連結清單,moves_up進行掃描資料;

2. 另一個cursor定位到branch節點,因為innodb b-tree結構的每一層都由雙向連結清單進行連接配接,然後這個cursor就沿着branch節點進行掃描,儲存掃描到的page_no,然後使用異步io,發起這些leaf page的預讀取。

mysql 5.6版本上的實作方式:

1. 在<code>row_search_for_mysql</code>進行moves_up的過程中進行logical read-ahead;

2. branch節點掃描的cursor儲存到trx結構中,生命周期到一個sql語句結束;

3. branch cursor掃描使用者可配置的page count,臨時儲存到數組中,對page_no進行排序;

4. 使用libaio發起異步io讀取,完成logical read-ahead。

logical read-ahead很好的提升了離散存儲資料的吞吐能力,facebook在他們的mysql執行個體的邏輯備份過程中,對于大表的dump備份開啟了此特性,備份速度有非常大的提升。

繼續閱讀