MySQL8.0 · 引擎特性 · InnoDB 批量讀特性
Note:
- 相關worklog:ofollow,noindex" target="_blank">WL#7093: Optimizer provides InnoDB with a bigger buffer
- 基於SQL/">MySQL8.0.12
通常情況下,InnoDB每獲得一行記錄會:
- 記錄下當前的cursor
- 返回記錄
- 下次進入innodb層時,重新恢復其在btree上的cursor,並讀取下一條記錄
但在滿足一定條件時,InnoDB會順序讀取一部分記錄並放到一個cache中。
- 讀取當前page的一些記錄
- 記錄cursor
- 返回記錄
- 再次進入Innodb層,直接從cache中取資料,如果cache已經取空,則繼續到btree上讀記錄
在之前的版本中,這個cache是由innodb來控制的,掛在row_prebuilt_t->fetch_cache陣列中,數量也是固定的,最多預讀8條記錄。
在MySQL8.0中,對這部分邏輯做了修改(wl#7093), 由server層來為innodb提供一個Buffer,並告訴innodb需要預讀多少條記錄。這種做法相比之前的版本顯然更加合理,因為只有server層才理解sql,知道隨後是否是順序scan,是否需要預讀更多的資料。server層通過估算可以去決定buffer的大小。
根據worklog的描述,執行器和innodb部分都會去決定是否使用record buffer.
執行器在如下場景不會使用record buffer:(refset_record_buffer(const QEP_TAB *tab)
)
- If the access type is not one of ref, ref_or_null, index_merge, range, index or ALL. - If the scan is estimated to return no more than one row. - If the scan is a loose index scan, which typically doesn't read many consecutive rows. - If the scan is against an internally generated temporary table. - If the storage engine reports that it won't use the buffer.
InnoDB在如下場景不會使用record buffer (refrow_prebuilt_t::can_prefetch_records()
):
- If the scan is not read-only. - If the scan accesses BLOB-based columns (such as BLOB, TEXT, JSON, GEOMETRY). - If it is a fulltext query. - If the table does not have a user-defined primary key or a unique constraint that could be used as a primary key. - Invoked from innodb api, aks: memcached plugin - Invoked by Handler syntax
一些細節:
row_search_end_range_check
其他相關函式:
row_sel_dequeue_cached_row_for_mysql() // 從buffer中讀取出記錄 row_sel_enqueue_cache_row_for_mysql() // 向buffer中快取記錄 row_sel_fetch_last_buf()