mysql物理优化器代价模型分析【原创】
1. 引言
mysql的sql server在根据where condition检索数据的时候,一般会有多种数据检索的方法,其会根据各种数据检索方法代价的大小,选择代价最小的那个数据检索方法。
比如说这个语句,where col1=x and col2=y and col3 >z , 同时存在inx_col1,inx_col2,inx_col3,inx_col1_col2_col3这四个索引,sql server要解决的问题有1)选择哪个索引、 2)是索引range扫描还是ref扫描、3)table scan的方式是否可行。
mysql会根据以下几种数据检索策略选择代价最小的策略来从数据表中获取数据,1)各个索引的range scan代价 2)各个索引的ref scan代价 3)table scan的代价。如何计算这些代价,是本文详细说明的重点。
总代价cost = cpu cost + io cost。
2 . 代价因子
mysql的代价因子在内存中有一份副本,由Server_cost_constants 和SE_cost_constants两个类组成。这两个类的具体数据成员如下。
Mysql Server 代价因子
Server_cost_constants {
m_row_evaluate_cost //行记录条件谓词评估代价
m_key_compare_cost //键值比较代价
m_memory_temptable_create_cost //内存临时表创建代价
m_memory_temptable_row_cost //内存临时表的行代价
m_disk_temptable_create_cost //磁盘临时表创建代价
m_disk_temptable_row_cost
}
存储引擎代价因子
SE_cost_constants{
m_memory_block_read_cost //从buffer pool中读取一个页面的代价
m_io_block_read_cost //从文件系统中读取一个页面的代价,buffer miss的场景
m_memory_block_read_cost_default
m_io_block_read_cost_default
}
mysql的代价因子在系统的持久化系统表中也有一份副本,对应mysql.server_cost 和 mysql.engine_cost两个表,这两个表中的字段与 内存中的类字段相同。DBA可以根据实际的硬件情况测试,测试出最适合的代价因子,然后update系统表中对应的字段。再然后执行flush OPTIMIZER_COSTS命令,将修改反应到内存中数据,这样新连接上来的mysql session会读取到内存中数据,然后以新的代价因子计算代价数。
代价因子如何根据实际的硬件环境与负载压力自适应地调整,是一个重要的研究课题。
3 . 统计信息
sql server需要的统计信息是由存储引擎innodb提供的,调用innodb提供的api可以获取这些统计信息,本文的后半部分会罗列这些api。innodb的统计信息根据需要可以持久化到系统表中。mysql.innodb_table_stats和mysql.innodb_index_stats存储了表的统计信息和索引的统计信息。
mysql.innodb_table_stats表中字段说明
database_name 库名
table_name 表名
n_rows 表中的数据行数
clustered_index_size 聚集索引的页面数
sum_of_other_index_sizes 其他非主键索引的页面数
last_update 最后更新这张表的时间
mysql.innodb_index_stats 表中字段说明
database_name 库名
table_name 表名
index_name 索引名
stat_name 统计项名称
stat_value 统计项值
sample_size 采样的页面数
last_update 最后更新这张表的时间 其中stat_name 统计项名称包括:
n_diff_pfxNN 为不同前缀列的cardinality,即不同前缀字段的 distinct value个数
n_leaf_page 索引叶子节点页面数目
size 索引页面数目
4. 代价的计算公式
cpu代价计算
double row_evaluate_cost(double rows)
{
return rows * m_server_cost_constants->row_evaluate_cost();
}
table scan IO代价计算
Cost_estimate handler::table_scan_cost()
{
double io_cost= scan_time() * table->cost_model()->page_read_cost(1.0);
}
ref and range scan IO代价计算
聚集索引扫描IO代价计算公式
Cost_estimate handler::read_cost(uint index, double ranges, double rows)
{
double io_cost= read_time(index, static_cast<uint>(ranges),
static_cast<ha_rows>(rows)) *
table->cost_model()->page_read_cost(1.0);
}
二级索引覆盖扫描(不需要回表)IO代价计算公式
Cost_estimate handler::index_scan_cost(uint index, double ranges, double rows)
{
double io_cost= index_only_read_time(index, rows) *
table->cost_model()->page_read_cost_index(index, 1.0);
}
二级索引非覆盖扫描(需要回表)IO代价计算公式
min( table→cost_model()→page_read_cost(tmp_fanout), tab→worst_seeks )
估算读取 pages个聚集索引页面所花费的代价, page数乘以代价因子
double Cost_model_table::page_read_cost(double pages)
估算读取 pages个指定 index索引页面所花费的代价数。
double Cost_model_table::page_read_cost_index(uint index, double pages)
5. innodb统计信息api
全表扫描聚集索引时,聚集索引(主键)占用的所有页面数
double ha_innobase::scan_time()
估算在聚集索引上,扫描 rows 条记录,需要读取的页面数
double ha_innobase::read_time(uint index, double ranges, double rows)
估算在指定 keynr索引进行覆盖扫描(不需要回表),扫描 records条记录,需要读取的索引页面数
double handler::index_only_read_time(uint keynr, double records)
估算指定 keynr索引在范围(min_key,max_key)中的记录数量
ha_innobase::records_in_range(
uint keynr, /*!< in: index number */
key_range *min_key, /*!< in: start key value of the
key_range *max_key) /*!< in: range end key val, may
)
估算聚集索引内存中页面数占其所有页面数的比率
double handler::table_in_memory_estimate()
估算二级索引内存中页面数占其所有页面数的比率
double handler::index_in_memory_estimate(uint keyno)
6.开启优化器跟踪
set session optimizer_trace="enabled=on"; explain your sql select * from information_schema.optimizer_trace;
7.优化器跟踪示例

"rows_estimation": [
{
"table": "`tab`",
"range_analysis": {
"table_scan": {
"rows": 5,
"cost": 4.1
},
"potential_range_indexes": [
{
"index": "PRIMARY",
"usable": false,
"cause": "not_applicable"
},
{
"index": "inx_clo2",
"usable": true,
"key_parts": [
"clo2",
"clo1"
]
},
{
"index": "inx_clo3",
"usable": true,
"key_parts": [
"clo3",
"clo1"
]
},
{
"index": "inx_clo2_clo3",
"usable": true,
"key_parts": [
"clo2",
"clo3",
"clo1"
]
}
],
"best_covering_index_scan": {
"index": "inx_clo2_clo3",
"cost": 2.0606,
"chosen": true
},
"setup_range_conditions": [
],
"group_index_range": {
"chosen": false,
"cause": "not_group_by_or_distinct"
},
"analyzing_range_alternatives": {
"range_scan_alternatives": [
{
"index": "inx_clo2",
"ranges": [
"hu <= clo2 <= hu"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 2,
"cost": 3.41,
"chosen": false,
"cause": "cost"
},
{
"index": "inx_clo3",
"ranges": [
"huan <= clo3 <= huan"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 1,
"cost": 2.21,
"chosen": false,
"cause": "cost"
},
{
"index": "inx_clo2_clo3",
"ranges": [
"hu <= clo2 <= hu AND huan <= clo3 <= huan"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": true,
"using_mrr": false,
"index_only": true,
"rows": 1,
"cost": 1.21,
"chosen": true
}
],
"analyzing_roworder_intersect": {
"intersecting_indexes": [
{
"index": "inx_clo2_clo3",
"index_scan_cost": 1,
"cumulated_index_scan_cost": 1,
"disk_sweep_cost": 0,
"cumulated_total_cost": 1,
"usable": true,
"matching_rows_now": 1,
"isect_covering_with_this_index": true,
"chosen": true
}
],
"clustered_pk": {
"clustered_pk_added_to_intersect": false,
"cause": "no_clustered_pk_index"
},
"chosen": false,
"cause": "too_few_indexes_to_merge"
}
},
"chosen_range_access_summary": {
"range_access_plan": {
"type": "range_scan",
"index": "inx_clo2_clo3",
"rows": 1,
"ranges": [
"hu <= clo2 <= hu AND huan <= clo3 <= huan"
]
},
"rows_for_plan": 1,
"cost_for_plan": 1.21,
"chosen": true
}
}
}
]
},
{
"considered_execution_plans": [
{
"plan_prefix": [
],
"table": "`tab`",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "ref",
"index": "inx_clo2",
"rows": 2,
"cost": 2.4,
"chosen": true
},
{
"access_type": "ref",
"index": "inx_clo3",
"rows": 1,
"cost": 1.2,
"chosen": true
},
{
"access_type": "ref",
"index": "inx_clo2_clo3",
"rows": 1,
"cost": 1.2,
"chosen": false
},
{
"rows_to_scan": 1,
"access_type": "range",
"range_details": {
"used_index": "inx_clo2_clo3"
},
"resulting_rows": 1,
"cost": 1.41,
"chosen": false
}
]
},
"condition_filtering_pct": 40,
"rows_for_plan": 0.4,
"cost_for_plan": 1.2,
"chosen": true
}
]
},
{
"attaching_conditions_to_tables": {
"original_condition": "((`tab`.`clo2` = 'hu') and (`tab`.`clo3` = 'huan'))",
"attached_conditions_computation": [
],
"attached_conditions_summary": [
{
"table": "`tab`",
"attached": "(`tab`.`clo2` = 'hu')"
}
]
}
},
{
"refine_plan": [
{
"table": "`tab`"
}
]
}
]
mysql物理优化器代价模型分析【原创】的更多相关文章
- [源码解析] PyTorch分布式优化器(3)---- 模型并行
[源码解析] PyTorch分布式优化器(3)---- 模型并行 目录 [源码解析] PyTorch分布式优化器(3)---- 模型并行 0x00 摘要 0x01 前文回顾 0x02 单机模型 2.1 ...
- MySQL追踪优化器小试
首先看一下MySQL追踪优化器的典型用法: 打开:SET optimizer_trace="enabled=on"; 查询优化器的信息:SELECT * FROM INFORMAT ...
- mysql之优化器、执行计划、简单优化
mysql之优化器.执行计划.简单优化 2018-12-12 15:11 烟雨楼人 阅读(794) 评论(0) 编辑 收藏 引用连接: https://blog.csdn.net/DrDanger/a ...
- keras channels_last、preprocess_input、全连接层Dense、SGD优化器、模型及编译
channels_last 和 channels_first keras中 channels_last 和 channels_first 用来设定数据的维度顺序(image_data_format). ...
- MySQL 性能优化神器 Explain 使用分析
简介 MySQL 提供了一个 EXPLAIN 命令, 它可以对 SELECT 语句进行分析, 并输出 SELECT 执行的详细信息, 以供开发人员针对性优化. EXPLAIN 命令用法十分简单, 在 ...
- MySQL Optimization 优化原理
MySQL Optimization 优化原理 MySQL逻辑架构 如果能在头脑中构建一幅MySQL各组件之间如何协同工作的架构图,有助于深入理解MySQL服务器.下图展示了MySQL的逻辑架构图. ...
- 详解MYSQL各种优化原理
说起MySQL的查询优化,相信大家收藏了一堆奇技淫巧:不能使用SELECT *.不使用NULL字段.合理创建索引.为字段选择合适的数据类型..... 你是否真的理解这些优化技巧?是否理解其背后的工作原 ...
- mysql数据库优化(转)
今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情.当我们去设计数据库表结构,对操作数据 ...
- MySQL 高性能优化实战总结
1 前言 2 优化的哲学 3 优化思路 3.1 优化什么 3.2 优化的范围有哪些 3.3 优化维度 4 优化工具有啥? 4.1 数据库层面 4.2 数据库层面问题解决思路 4.3 系统层面 4.4 ...
随机推荐
- MAC 上编译安装nginx-rtmp-module 流媒体服务器
MAC 上编译安装nginx-rtmp-module 流媒体服务器 记录踩坑过程 下载nginx和nginx-rtmp-module wget http://nginx.org/download/ng ...
- 微服务实战SpringCloud之Spring Cloud Feign替代HTTP Client
简介 在项目中我们有时候需要调用第三方的API,微服务架构中这种情况则更是无法避免--各个微服务之间通信.比如一般的项目中,有时候我们会使用 HTTP Client 发送 HTTP 请求来进行调用,而 ...
- html加C#上传文件
最近在学上传文件部分内容,包括创建文件夹,设置文件夹属性,上传文件并保存. 前台代码: <html xmlns="http://www.w3.org/1999/xhtml"& ...
- Java实现打开google浏览器
说明: 博主的Google浏览器版本:75.0.3770.142,如果运行异常,需要自行查找对应版本的驱动(chromedriver.exe) 需要的jar包: https://pan.baidu.c ...
- Windows安装tensorflow教程 GPU版
PS:这是GPU版本,CPU版会用笔记本环境另写一篇博客. 前置准备 查看GPU型号 电脑桌面->右键我的电脑->选择管理->点击设备管理器 如下图: 如果不是英伟达显卡,那么不用 ...
- python基础 画图
python 画图 matplotlib 库只保存图片,不显示图片? 在导入库时,添加如下代码 import matplotlib matplotlib.use('Agg') 各种 symbol ? ...
- 将微服务部署到 Azure Kubernetes 服务 (AKS) 实践
本文是对 <.NET Tutorial - Deploy a microservice to Azure> 的翻译和实践.入门级踩坑实践,k8s 大佬请回避,以免耽误您宝贵的时间. 介绍 ...
- [计算机网络]图解HTTP阅读笔记
总述 书的定位:一本十分浅显的HTTP书籍,主要介绍了HTTP与HTTPS.适合入门了解,很多地方都是蜻蜓点水,但稍微深入的地方能让人了解重点在哪,后面应该有针对性地阅读深入书籍. 主要内容:介绍了T ...
- react项目结合echarts,百度地图实现热力图
一.最近在一个react项目(antd pro)中需要展示一个热力地图.需求是: 1.热力地图可缩放: 2.鼠标点击可以展示该点地理坐标,及热力值. 3.初始化时候自适应展示所有的热力点. 4.展示热 ...
- archaius(2) 配置源
上一节讲到,archaius实现动态配置的核心就是定时去配置中心拉去配置内容,接下来几接就来看一下archaius内部具体是如何实现的. 首先我们来了解一下配置源,什么是配置源呢,archaius内部 ...