MySQL8.0 · 优化器新特性 · Cost Model, 直方图及优化器开销优化
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
MySQL當(dāng)前已經(jīng)發(fā)布到MySQL8.0版本,在新的版本中,可以看到MySQL之前被人詬病的優(yōu)化器部分做了很多的改動(dòng),由于筆者之前的工作環(huán)境是5.6,最近切換到最新的8.0版本,本文涵蓋了一些本人感興趣的和優(yōu)化器相關(guān)的部分,主要包括MySQL5.7的cost model以及MySQL8.0的直方圖功能。
本文基于當(dāng)前最新的MySQL8.0.12版本,主要是講下cost model 和 histogram的用法和相關(guān)代碼
Cost Model
Configurable cost constants
為什么需要配置cost model常量 ? 我們知道MySQL已經(jīng)發(fā)展了好幾十年的歷史,但是在優(yōu)化器中依然使用了hardcode的權(quán)重值來(lái)衡量io, cpu等資源情況,而這些權(quán)重值實(shí)際上是基于多年前甚至十來(lái)年前的經(jīng)驗(yàn)設(shè)定的。想想看,這么多年硬件的發(fā)展多么迅速。幾十上百個(gè)核心的服務(wù)器不在少數(shù)甚至在某些大型公司大規(guī)模使用,ssd早就成為主流,NVME也在崛起。高速RDMA網(wǎng)絡(luò)正在走入尋常百姓家。這一切甚至影響到數(shù)據(jù)庫(kù)系統(tǒng)的實(shí)現(xiàn)和變革。顯而易見,那些hardcode的權(quán)值已經(jīng)過(guò)時(shí)了,我們需要提供給用戶可定義的方式,甚至更進(jìn)一步的,能夠智能的根據(jù)硬件環(huán)境自動(dòng)設(shè)定。
MySQL5.7引入兩個(gè)新的系統(tǒng)表, 通過(guò)這兩個(gè)系統(tǒng)表暴露給用戶來(lái)進(jìn)行更新,如下:
root@(none) 04:05:24>select * from mysql.server_cost; +------------------------------+------------+---------------------+---------+---------------+ | cost_name | cost_value | last_update | comment | default_value | +------------------------------+------------+---------------------+---------+---------------+ | disk_temptable_create_cost | NULL | 2018-04-23 13:55:20 | NULL | 20 | | disk_temptable_row_cost | NULL | 2018-04-23 13:55:20 | NULL | 0.5 | | key_compare_cost | NULL | 2018-04-23 13:55:20 | NULL | 0.05 | | memory_temptable_create_cost | NULL | 2018-04-23 13:55:20 | NULL | 1 | | memory_temptable_row_cost | NULL | 2018-04-23 13:55:20 | NULL | 0.1 | | row_evaluate_cost | NULL | 2018-04-23 13:55:20 | NULL | 0.1 | +------------------------------+------------+---------------------+---------+---------------+ 6 rows in set (0.00 sec)其中default_value是generated column,其表達(dá)式已經(jīng)固定死了默認(rèn)值:`default_value` float GENERATED ALWAYS AS ( (case `cost_name` when _utf8mb3'disk_temptable_create_cost' then 20.0 when _utf8mb3'disk_temptable_row_cost' then 0.5 when _utf8mb3'key_compare_cost' then 0.05 when _utf8mb3'memory_temptable_create_cost' then 1.0 when _utf8mb3'memory_temptable_row_cost' then 0.1 when _utf8mb3'row_evaluate_cost' then 0.1 else NULL end)) VIRTUALroot@(none) 04:05:35>select * from mysql.engine_cost; +-------------+-------------+------------------------+------------+---------------------+---------+---------------+ | engine_name | device_type | cost_name | cost_value | last_update | comment | default_value | +-------------+-------------+------------------------+------------+---------------------+---------+---------------+ | default | 0 | io_block_read_cost | NULL | 2018-04-23 13:55:20 | NULL | 1 | | default | 0 | memory_block_read_cost | NULL | 2018-04-23 13:55:20 | NULL | 0.25 | +-------------+-------------+------------------------+------------+---------------------+---------+---------------+你可以通過(guò)update語(yǔ)句來(lái)進(jìn)行更新, 例如:
root@(none) 04:05:52>update mysql.server_cost set cost_value = 40 where cost_name = 'disk_temptable_create_cost'; Query OK, 1 row affected (0.05 sec) Rows matched: 1 Changed: 1 Warnings: 0root@(none) 04:07:13>select * from mysql.server_cost where cost_name = 'disk_temptable_create_cost'; +----------------------------+------------+---------------------+---------+---------------+ | cost_name | cost_value | last_update | comment | default_value | +----------------------------+------------+---------------------+---------+---------------+ | disk_temptable_create_cost | 40 | 2018-06-23 16:07:05 | NULL | 20 | +----------------------------+------------+---------------------+---------+---------------+ 1 row in set (0.00 sec)//更新后執(zhí)行一次flush optimizer_costs操作來(lái)更新內(nèi)存 //但老的session還是會(huì)用老的cost數(shù)據(jù) root@(none) 10:10:12>flush optimizer_costs; Query OK, 0 rows affected (0.00 sec)可以看到用法也非常簡(jiǎn)單,上面包含了兩張表:server_cost及engine_cost,分別對(duì)server層和引擎層進(jìn)行配置
相關(guān)代碼:
全局cache Cost_constant_cache
全局cache維護(hù)了一個(gè)當(dāng)前的cost model信息, 用戶線程在lex_start時(shí)會(huì)去判斷其有沒(méi)有初始化本地指針,如果沒(méi)有的話就去該cache中將指針拷貝到本地
初始化全局cache:
Cost_constant_cache::init :創(chuàng)建Cost_model_constants, 其中包含了兩類信息: server層cost model和引擎層cost model, 類結(jié)構(gòu)如下:Cost_constant_cache ----> Cost_model_constants---> Server_cost_constants//server_cost---> Cost_model_se_info --->SE_cost_constants//engine_cost 如果存儲(chǔ)引擎提供了接口函數(shù)get_cost_constants的話,則從存儲(chǔ)引擎那取從系統(tǒng)表讀取配置,適用于初始化和flush optimizer_costs并更新cache:
read_cost_constants() |--> read_server_cost_constants |--> read_engine_cost_constants由于用戶可以動(dòng)態(tài)的更新系統(tǒng)表,執(zhí)行完flush optimizer_costs后,有可能老的版本還在被某些session使用,因此需要引用計(jì)數(shù),老的版本ref counter被降為0后才能被釋放
線程cost model初始化
- Cost_model_server
在每個(gè)線程的thd上,掛了一個(gè)Cost_model_server的對(duì)象THD::m_cost_model, 在lex_start()時(shí),如果發(fā)現(xiàn)線程的m_cost_model沒(méi)有初始化,就會(huì)去獲取全局的指針,存儲(chǔ)到本地:
Cost_model_server::initconst Cost_model_constants *m_cost_constants = cost_constant_cache->get_cost_constants(); // 會(huì)增加一個(gè)引用計(jì)數(shù),以確保不會(huì)在引用時(shí)被刪除const Server_cost_constants *m_server_cost_constants = m_cost_constants->get_server_cost_constants(); // 同樣獲取的是全局指針可見thd不創(chuàng)建自己的cost model, 只引用cache中的指針
Table Cost Model
struct TABLE::m_cost_model, 類型:Cost_model_table
其值取自上述thd中存儲(chǔ)的cost model對(duì)象
Cost_estimate
統(tǒng)一的對(duì)象類型cost_estimate來(lái)存儲(chǔ)計(jì)算的cost結(jié)果,包含四個(gè)維度:
double io_cost; ///< cost of I/O operationsdouble cpu_cost; ///< cost of CPU operationsdouble import_cost; ///< cost of remote operationsdouble mem_cost; ///< memory used (bytes)未來(lái)
目前來(lái)看,除非根據(jù)工作負(fù)載,經(jīng)過(guò)充分的測(cè)試才能得出合理的配置值,但如何配置,什么是合理的值,個(gè)人認(rèn)為應(yīng)該是可以自動(dòng)調(diào)整配置的。關(guān)鍵是找出配置和硬件條件的對(duì)應(yīng)關(guān)系。 這也是我們未來(lái)可以努力的一個(gè)方向。
reference:
1. Cost Model官方文檔
2. 官方博客1:The MySQL Optimizer Cost Model Project
3. 官方博客2: A new dimension to MySQL query optimizations?
4. Optimizer Cost Model Improvements in MySQL 5.7.5 DMR
5.Slide: MySQL Cost Model
Related Worklog:
WL#7182: Optimizer Cost Model API?
WL#7209: Handler interface changes for new cost model
WL#7276: Configuration data base for Optimizer Cost Model
WL#7315 Optimizer cost model: main memory management of cost constants
WL#7316 Optimizer cost model: Command for online updating of cost model constants
Histogram
直方圖也是MySQL一個(gè)萬(wàn)眾期待的功能了,這個(gè)功能實(shí)際上在其他數(shù)據(jù)庫(kù)產(chǎn)品中是很常見的,可以很好的指導(dǎo)優(yōu)化器選擇執(zhí)行路徑。利用直方圖存儲(chǔ)了指定列的數(shù)據(jù)分布。MariaDB從很早的10.0.2版本支持這個(gè)功能, 而MySQL在最新的8.0版本中也開始支持
使用
MySQL里使用直方圖是通過(guò)ANALYZE TABLE語(yǔ)法來(lái)執(zhí)行:
ANALYZE [NO_WRITE_TO_BINLOG | LOCAL]TABLE tbl_nameUPDATE HISTOGRAM ON col_name [, col_name] ...[WITH N BUCKETS]ANALYZE [NO_WRITE_TO_BINLOG | LOCAL]TABLE tbl_nameDROP HISTOGRAM ON col_name [, col_name] ...舉個(gè)簡(jiǎn)單的例子:
我們以普通的sysbench表為例:root@sb1 05:16:33>show create table sbtest1\G *************************** 1. row ***************************Table: sbtest1 Create Table: CREATE TABLE `sbtest1` (`id` int(11) NOT NULL AUTO_INCREMENT,`k` int(11) NOT NULL DEFAULT '0',`c` char(120) NOT NULL DEFAULT '',`pad` char(60) NOT NULL DEFAULT '',PRIMARY KEY (`id`),KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=200001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.01 sec)# 創(chuàng)建直方圖并存儲(chǔ)到數(shù)據(jù)詞典中root@sb1 05:16:38>ANALYZE TABLE sbtest1 UPDATE HISTOGRAM ON k with 10 BUCKETS; +-------------+-----------+----------+----------------------------------------------+ | Table | Op | Msg_type | Msg_text | +-------------+-----------+----------+----------------------------------------------+ | sb1.sbtest1 | histogram | status | Histogram statistics created for column 'k'. | +-------------+-----------+----------+----------------------------------------------+ 1 row in set (0.55 sec)root@sb1 05:17:03>ANALYZE TABLE sbtest1 UPDATE HISTOGRAM ON k,pad with 10 BUCKETS; +-------------+-----------+----------+------------------------------------------------+ | Table | Op | Msg_type | Msg_text | +-------------+-----------+----------+------------------------------------------------+ | sb1.sbtest1 | histogram | status | Histogram statistics created for column 'k'. | | sb1.sbtest1 | histogram | status | Histogram statistics created for column 'pad'. | +-------------+-----------+----------+------------------------------------------------+ 2 rows in set (7.98 sec)刪除pad列上的histogram: root@sb1 05:17:51>ANALYZE TABLE sbtest1 DROP HISTOGRAM ON pad; +-------------+-----------+----------+------------------------------------------------+ | Table | Op | Msg_type | Msg_text | +-------------+-----------+----------+------------------------------------------------+ | sb1.sbtest1 | histogram | status | Histogram statistics removed for column 'pad'. | +-------------+-----------+----------+------------------------------------------------+ 1 row in set (0.06 sec)root@sb1 05:58:12>ANALYZE TABLE sbtest1 DROP HISTOGRAM ON k; +-------------+-----------+----------+----------------------------------------------+ | Table | Op | Msg_type | Msg_text | +-------------+-----------+----------+----------------------------------------------+ | sb1.sbtest1 | histogram | status | Histogram statistics removed for column 'k'. | +-------------+-----------+----------+----------------------------------------------+ 1 row in set (0.08 sec)# 如果不指定bucket的話,默認(rèn)Bucket的數(shù)量是100root@sb1 05:58:27>ANALYZE TABLE sbtest1 UPDATE HISTOGRAM ON k; +-------------+-----------+----------+----------------------------------------------+ | Table | Op | Msg_type | Msg_text | +-------------+-----------+----------+----------------------------------------------+ | sb1.sbtest1 | histogram | status | Histogram statistics created for column 'k'. | +-------------+-----------+----------+----------------------------------------------+ 1 row in set (0.56 sec)直方圖統(tǒng)計(jì)信息存儲(chǔ)于InnoDB數(shù)據(jù)詞典中,可以通過(guò)information_schema表來(lái)獲取
root@information_schema 05:34:49>SHOW CREATE TABLE INFORMATION_SCHEMA.COLUMN_STATISTICS\G *************************** 1. row ***************************View: COLUMN_STATISTICSCreate View: CREATE ALGORITHM=UNDEFINED DEFINER=`mysql.infoschema`@`localhost` SQL SECURITY DEFINER VIEW `COLUMN_STATISTICS` AS select `mysql`.`column_statistics`.`schema_name` AS `SCHEMA_NAME`,`mysql`.`column_statistics`.`table_name` AS `TABLE_NAME`,`mysql`.`column_statistics`.`column_name` AS `COLUMN_NAME`,`mysql`.`column_statistics`.`histogram` AS `HISTOGRAM` from `mysql`.`column_statistics` where can_access_table(`mysql`.`column_statistics`.`schema_name`,`mysql`.`column_statistics`.`table_name`) character_set_client: utf8 collation_connection: utf8_general_ci 1 row in set (0.00 sec)從column_statistics表的定義可以看到,有一個(gè)名為mysql.column_statistics系統(tǒng)表,但被隱藏了,沒(méi)有對(duì)外暴露
以下舉個(gè)簡(jiǎn)單的例子:
root@sb1 05:58:55>ANALYZE TABLE sbtest1 UPDATE HISTOGRAM ON k WITH 4 BUCKETS; +-------------+-----------+----------+----------------------------------------------+ | Table | Op | Msg_type | Msg_text | +-------------+-----------+----------+----------------------------------------------+ | sb1.sbtest1 | histogram | status | Histogram statistics created for column 'k'. | +-------------+-----------+----------+----------------------------------------------+ 1 row in set (0.63 sec)# 查詢表上的直方圖信息root@sb1 06:00:43>SELECT JSON_PRETTY(HISTOGRAM) FROM INFORMATION_SCHEMA.COLUMN_STATISTICS WHERE SCHEMA_NAME='sb1' AND TABLE_NAME = 'sbtest1'\G *************************** 1. row *************************** JSON_PRETTY(HISTOGRAM): {"buckets": [[38671,99756,0.249795,17002],[99757,100248,0.500035,492],[100249,100743,0.749945,495],[100744,172775,1.0,16630]],"data-type": "int","null-values": 0.0,"collation-id": 8,"last-updated": "2018-09-22 09:59:30.857797","sampling-rate": 1.0,"histogram-type": "equi-height","number-of-buckets-specified": 4 } 1 row in set (0.00 sec)從輸出的json可以看到,在執(zhí)行了上述語(yǔ)句后產(chǎn)生的直方圖,有4個(gè)bucket,數(shù)據(jù)類型為Int, 類型為equi-height,即等高直方圖(另外一種是等寬直方圖,即SINGLETON)。每個(gè)Bucket中,描述的信息包括:數(shù)值的上界和下界, 頻率以及不同值的個(gè)數(shù)。通過(guò)這些信息可以獲得比較精確的數(shù)據(jù)分布情況,從而優(yōu)化器來(lái)根據(jù)這些統(tǒng)計(jì)信息決定更優(yōu)的執(zhí)行計(jì)劃。
如果列上存在大量的重復(fù)值,那么MySQL也可能選擇等寬直方圖,例如上例,我們將列k上的值更新為一半10一半為20, 那么出來(lái)的直方圖數(shù)據(jù)如下:
root@sb1 10:41:17>SELECT JSON_PRETTY(HISTOGRAM) FROM INFORMATION_SCHEMA.COLUMN_STATISTICS WHERE SCHEMA_NAME='sb1' AND TABLE_NAME = 'sbtest1'\G *************************** 1. row *************************** JSON_PRETTY(HISTOGRAM): {"buckets": [[10,0.499995],[20,1.0]],"data-type": "int","null-values": 0.0,"collation-id": 8,"last-updated": "2018-09-22 14:41:17.312601","sampling-rate": 1.0,"histogram-type": "singleton","number-of-buckets-specified": 100 } 1 row in set (0.00 sec)如上,對(duì)于SINGLETON類型,每個(gè)bucket只包含兩個(gè)值:列值,及對(duì)應(yīng)的累計(jì)頻率(即百分之多少的數(shù)據(jù)比當(dāng)前Bucket里的值要小或相等)
注意這里的sampling-rate, 這里的值為1,表示讀取了表上所有的數(shù)據(jù)來(lái)進(jìn)行統(tǒng)計(jì),但通常對(duì)于大表而言,我們可能不希望讀太多的數(shù)據(jù),因?yàn)榭赡墚a(chǎn)生過(guò)度的內(nèi)存消耗,因此MySQL還提供了一個(gè)參數(shù)histogram_generation_max_mem_size來(lái)限制內(nèi)存的使用上限。
如果表上的DML不多,那直方圖基本是穩(wěn)定的,但頻繁寫入的話,那我們就可能需要去定期更新直方圖,MySQL本身不會(huì)去主動(dòng)更新。
優(yōu)化器通過(guò)histogram來(lái)計(jì)算列的過(guò)濾性,大多數(shù)的謂詞都可以使用到。具體參閱官方文檔
關(guān)于直方圖影響查詢計(jì)劃,這篇博客?及?這篇博客
相關(guān)代碼
代碼結(jié)構(gòu):
以MySQL8.0.12為例,主要代碼在sql/histogram目錄下:
創(chuàng)建及存儲(chǔ)histogram:
處理histogram的相關(guān)函數(shù)和堆棧如下:
Sql_cmd_analyze_table::handle_histogram_command |--> update_histogram //更新histogram|-->histograms::update_histogram //調(diào)用namespace內(nèi)的接口函數(shù)a. 判斷各個(gè)列://histograms::field_type_to_value_map_type: 檢查列類型是否支持//covered_by_single_part_index: 如果列是Pk或者uk,不會(huì)為其創(chuàng)建histogram//如果是generated column, 則找到其依賴的列加入到set中b. 判斷取樣的半分比,這主要受參數(shù)histogram_generation_max_mem_size限制,如果設(shè)的足夠大,則會(huì)去讀取全表數(shù)據(jù)進(jìn)行分析|-> fill_value_maps //開始從表上讀取需要分析的列數(shù)據(jù)|->ha_sample_init|->ha_sample_next|--> handler::sample_next //讀取下一條記錄,通過(guò)隨機(jī)數(shù)的方式來(lái)進(jìn)行取樣Value_map<T>::add_values // 將讀到的數(shù)據(jù)加入到map中|->...|->ha_sample_end|-> build_histogram //創(chuàng)建histogram對(duì)象a. 確定histogram類型:如果值的個(gè)數(shù)小于桶的個(gè)數(shù),則使用Singleton,否則使用Equi_height類型|->Singleton<T>::build_histogram|->Equi_height<T>::build_histogram|-> Histogram::store_histogram //將histogram信息存儲(chǔ)到column_statistic表中|-> dd::cache::Dictionary_client::update<dd::Column_statistics>|--> drop_histogram //刪除直方圖使用histogram
使用的方式就比較簡(jiǎn)單了:
首先在表對(duì)象TABLE_SHARE中,增加成員m_histograms,其結(jié)構(gòu)為一個(gè)unordered map,key值為field index, value為相應(yīng)的histogram對(duì)象
獲取列值過(guò)濾性的相關(guān)堆棧如下:
get_histogram_selectivity|-->Histogram::get_selectivity|->get_equal_to_selectivity_dispatcher|->get_greater_than_selectivity_dispatcher|->get_less_than_selectivity_dispatcher|-->write_histogram_to_trace // 寫到optimizer_trace中MySQL支持多種操作類型對(duì)直方圖的使用,包括:
col_name = constant col_name <> constant col_name != constant col_name > constant col_name < constant col_name >= constant col_name <= constant col_name IS NULL col_name IS NOT NULL col_name BETWEEN constant AND constant col_name NOT BETWEEN constant AND constant col_name IN (constant[, constant] ...) col_name NOT IN (constant[, constant] ...)通過(guò)直方圖,我們可以根據(jù)列上的條件判斷出列值的過(guò)濾性,來(lái)輔助選擇更優(yōu)的執(zhí)行計(jì)劃。在沒(méi)有直方圖之前我們需要通過(guò)在列上建立索引來(lái)獲得相對(duì)精確的列值分布。但我們知道索引是有很大的維護(hù)開銷的,而直方圖則可以靈活的按需創(chuàng)建。
reference
WL#5384 PERFORMANCE_SCHEMA, HISTOGRAMS
WL#8706 Persistent storage of Histogram data
WL#8707 Classes/structures for Histograms
WL#8943 Extend ANALYZE TABLE with histogram support
WL#9223 Using histogram statistics in the optimizer
其他
優(yōu)化rec_per_key
相關(guān)worklog:
WL#7338: Interface for improved records per key estimates
WL#7339 Use improved records per key estimate interface in optimizer
MySQL通過(guò)rec_per_key 接口來(lái)估算記錄的個(gè)數(shù)(暗示每個(gè)索引Key對(duì)應(yīng)的記錄個(gè)數(shù)),但在早前版本中這個(gè)數(shù)字是整數(shù),對(duì)于小數(shù)會(huì)取整,不能表示準(zhǔn)確的rec_per_key,從而影響到索引的選擇,因此在5.7版本中,將其記錄的值改成了float類型
引入數(shù)據(jù)cache狀態(tài)計(jì)算開銷
相關(guān)worklog:
WL#7168 API for estimates for how much of table and index data that is in memory buffer
WL#7170: InnoDB buffer estimates for tables and indexes
WL#7340 IO aware cost estimate function for data access
在之前的版本中,優(yōu)化器是無(wú)法知道數(shù)據(jù)的狀態(tài),是否是cache在內(nèi)存中,還是需要從磁盤讀出來(lái)的,缺乏這部分信息,導(dǎo)致優(yōu)化器統(tǒng)一認(rèn)為數(shù)據(jù)屬于磁盤的來(lái)計(jì)算開銷。這可能導(dǎo)致低效的執(zhí)行計(jì)劃。
相關(guān)代碼:
server層新增api,用于獲取表或索引上有百分之多少的數(shù)據(jù)是存儲(chǔ)在cache中的
handler::table_in_memory_estimatehandler::index_in_memory_estimate而在innodb層,增加了一個(gè)全局變量buf_stat_per_index?(對(duì)應(yīng)類型為buf_stat_per_index_t) 來(lái)維護(hù)每個(gè)索引在內(nèi)存中的leaf page個(gè)數(shù), 其內(nèi)部實(shí)現(xiàn)了一個(gè)lock-free的hash結(jié)構(gòu),Key值為(m_space_id) << 32 | m_index_id), 在讀入page時(shí)或者內(nèi)存中創(chuàng)建新page時(shí), 如果對(duì)應(yīng)的page是leaf page,就遞增計(jì)數(shù);當(dāng)從page hash中移除時(shí),則遞減計(jì)數(shù)。
為了減少性能的影響,計(jì)數(shù)器是通過(guò)lock-free hash的結(jié)構(gòu)存儲(chǔ)的,對(duì)應(yīng)的結(jié)構(gòu)為ut_lock_free_hash_t。
基本的實(shí)現(xiàn)思路是:hash是一個(gè)定長(zhǎng)的數(shù)組,數(shù)組元素為(key, val), 根據(jù)Key計(jì)算一個(gè)hash值再模上array size, 找到對(duì)應(yīng)的槽位, 如果槽位被占用了,則向右查找一個(gè)空閑的slot。
當(dāng)數(shù)組滿了的時(shí)候,會(huì)創(chuàng)建一個(gè)新的更大的數(shù)組,在數(shù)據(jù)還沒(méi)Move到這個(gè)新hash之前,所有的search都需要查詢兩個(gè)數(shù)組。當(dāng)所有的記錄到遷移到新數(shù)組,并且沒(méi)有線程訪問(wèn)老的數(shù)組時(shí),就可以把老的hash刪除掉了。
在hash中存儲(chǔ)的counter本身,也考慮到多核和numa架構(gòu),避免同時(shí)更新引起的cpu cache失效。在大量core的場(chǎng)景下這個(gè)問(wèn)題可能很明顯。Innodb封裝計(jì)數(shù)操作到類ut_lock_free_cnt_t中,使用數(shù)組維護(hù)counter, 按照cpu no作為index更新,需要獲取counter值時(shí)則累加數(shù)組中的值。
這個(gè)Lock free hash并不是個(gè)通用場(chǎng)景的hash結(jié)構(gòu):例如處理沖突的時(shí)候,可能占用其他key的槽位,hash不夠用時(shí),需要遷移到新的array中。實(shí)際上mysql本身實(shí)現(xiàn)了一個(gè)lf_hash,在擴(kuò)展Hash時(shí)無(wú)需遷移數(shù)據(jù),有空單獨(dú)開篇博客講一下。
你可以從information_schema.innodb_cached_indexes表中讀取到每個(gè)索引cache的page個(gè)數(shù)。
當(dāng)定義好接口,并且Innodb提供相應(yīng)的統(tǒng)計(jì)數(shù)據(jù)后,優(yōu)化器就可以利用這些信息來(lái)計(jì)算開銷:
- Cost_model_table::page_read_cost
- Cost_model_table::page_read_cost_index
轉(zhuǎn)載于:https://my.oschina.net/u/3943837/blog/2218823
總結(jié)
以上是生活随笔為你收集整理的MySQL8.0 · 优化器新特性 · Cost Model, 直方图及优化器开销优化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 搞懂Java分布式锁实现看这篇文章就对了
- 下一篇: 浅谈MySQL的七种锁