记录MySQL 5.5上,优化器进行cost计算的方法。

第一篇: 单表的cost计算

数据结构:

1. table_share: 包含了表的元数据,其中索引部分:

key_info:一个key的结构体,代表一个索引,包含了:

key_length:key的长度

key_parts:key一共有多少个column

key_part:key中具体的column

rec_per_key:相同的key平均有几条记录

例如:

(gdb) p (table->s->key_info->name)

$16 = 0x8ca0ffbd "PRIMARY"

(gdb) p (table->s->key_info->key_parts)

$17 = 1

(gdb) p (table->s->key_info->rec_per_key)

$18 = (ulong *) 0x8ca0ffe8

2. JOIN:

mysql_select函数中,创建了 new JOIN(thd, fields, select_options, result)对象,包含了当前查询的所有组件和各种转换结果,其中 :

prepare:进行一些等价交换之类的变化

optimize:选择join的方式和access path

exec:根据执行计划运行查询

3. join_tab:

包含了一个table访问的cost等一些信息,经过优化后,填充这个结构体

cost的计算方法

cost = cpu cost + io cost

cpu cost:server层对返回的记录数的compare时间

io cost:引擎层根据扫描记录的记录数计算cost

统计信息

这里用到了两部分统计信息:

1. server层的统计信息,保存在table_share中。包括:

key_length

rec_per_key

block_size等

2. innodb层的统计信息,包括:

stat_n_rows

stat_clustered_index_size

stat_sum_of_other_index_size

主要函数调用

make_join_statistics:

--update_ref_and_keys: 添加可以使用的索引。

--get_quick_record_count:

----test_quick_select: 评估每一个join table查询得到的记录数,其中比较不同index的cost, 返回的记录数,选择最优的那个。

choose plan:选择join的顺序

实验过程

CREATE TABLE `xpchild` (

`id` int(11) NOT NULL,

`name` varchar(100) DEFAULT NULL,

`c1` int(11) DEFAULT NULL,

`c2` int(11) DEFAULT NULL,

PRIMARY KEY (`id`),

KEY `xpchild_name` (`name`),

KEY `xpchild_id_c1` (`id`,`c1`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1

实验1: 单值查询

explain select * from xpchild where id =100;

函数调用栈:

make_join_statistics:

table->quick_condition_rows= table->file->stats.records;

if (s->type == JT_SYSTEM || s->type == JT_CONST)

s->found_records=s->records=s->read_time=1; s->worst_seeks=1.0;

结论:单key的查询,join_tab的type=JT_CONST,索引record和read time都是1;最终得到的join->best_read=1.0;

实验2: 范围查询

explain select * from xpchild where id > 100;

step1:update_ref_and_keys: 一共得到两个possible index,

step2:test_quick_select

1. 计算全表扫描的cost:

innodb全表扫描的io cost:

innodb的io cost: s->read_time=(ha_rows) s->table->file->scan_time();

innodb scan time:prebuilt->table->stat_clustered_index_size

等于innodb这张表的聚簇索引的page个数,本身innodb就是聚簇索引表,这里计算的io cost=16

(gdb) p s->read_time

$7 = 16

MySQL server的cpu cost:

scan_time= (double) records / TIME_FOR_COMPARE + 1;

(gdb) p scan_time

$16 = 1359.4000000000001

总的cost:read_time= (double) head->file->scan_time() + scan_time + 1.1;

(gdb) p read_time

$18 = 1376.5

继续函数栈:

根据possible index,生成sel_tree;

get_best_group_min_max: 这里没有使用到

get_key_scans_params:根据sel_tree找到更好的cost

2. 计算full index的cost

find_shortest_key: 在覆盖索引中选择length最短的那个。

get_index_only_read_time:这里如果有覆盖索引(covering index)那么就会计算此覆盖索引的cost。

full index scan的计算方法:

uint keys_per_block= (param->table->file->stats.block_size/2/

(param->table->key_info[keynr].key_length+

param->table->file->ref_length) + 1);

read_time=((double) (records+keys_per_block-1)/(double) keys_per_block);

这里假设:一个块中,只使用了一半的空间写入数据,

如果计算的key_read_time > read_time, 则read_time= key_read_time,从此不再使用全表扫描。

3. pk 索引计算的cost

进入get_key_scans_params函数:选择比传入的read_time小的cost的执行计划,生成一个TRP_RANGE对象返回。

step1: 评估范围扫描的记录数(check_quick_select)

check_quick_keys:根据key,min,max值来评估记录数,并把records记录到table->quick_rows[key]中,以便后续需要。

(gdb) p *min_key

$82 = 100 'd'

ha_innobase::records_in_range: innodb引擎根据min和max值来评估记录数。

计算方法:innodb对b_tree中范围确定的page的个数和record_per_page进行计算,当评估>all_record/2时,就取all_record/2。

(gdb) p records

$112 = 3396

step 2: 计算cost

根据pk range估算的records=3396,调整table->quick_condition_rows从全表的6792到现在的3396。

计算cost:

cpu_cost= (double) found_records / TIME_FOR_COMPARE;

cpu_cost= 679.20000000000005

io_cost = param->table->file->read_time(keynr,param->range_count,found_records);

found_read_time = cpu_cost + io_cost + 0.01

found_read_time = 683.74750000000006

这样,通过pk扫描的cost远小于前面第一阶段的全表扫描的代价。

4. 计算普通索引的cost

因为都可以使用前导列进行查询,查询的效率的差别在于非主键索引需要回到聚簇索引中查询非索引列。

所以,innodb返回的found_rows=6556(包含了扫描索引xpchild_id_c1 和primary key的), 所以最终计算的cost大于使用pk的cost。

最终计算得到的cost=7868.21 远高于pk索引的cost。

结论: 最终选择了pk的索引进行range扫描

下一篇实验待续:关联查询。

mysql 优化器 cost评估_MySQL优化器cost计算相关推荐

  1. mysql性能调优快捷键_mysql优化篇

    mysql优化篇 2019-4-12 hubo 数据库 优化目标 1.减少 IO 次数 IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作 ...

  2. 优化mysql的21个建议_MySQL优化小建议

    MySQL优化小建议 洛逸 发布于 2019-11-04 12:03 背景 "那啥,你过来一下!" "怎么了?我代码都单元测试了的,没出问题啊!"我一脸懵逼跑到 ...

  3. mysql 优化器关联查询_MySQL 查询优化器(二)

    1.6多个查询字段(常量条件) 多个查询字段的查询处理逻辑如下所示: JOIN:prepare阶段 setup_tables():同1.1测试. setup_fields():同1.1测试. setu ...

  4. mysql优化 博客园_MySQL优化

    MySQL优化步骤 首先学会如何定位到SQL语句 1.1查看SQL语句的执行次数 在MySQL中可以通过命令查看服务器该表状态信息 show status like 'Com_______'; 如果想 ...

  5. mysql索引空间太大_MySQL优化索引

    1.  MySQL如何使用索引 索引用于快速查找具有特定列值的行.如果没有索引,MySQL必须从第一行开始,然后遍历整个表以找到相关的行.表越大,花费越多.如果表中有相关列的索引,MySQL可以快速确 ...

  6. mysql最大并行用户设置_mysql 优化配置

    1.目的: 通过根据服务器目前状况,修改Mysql的系统参数,达到合理利用服务器现有资源,最大合理的提高MySQL性能. 2.服务器参数: 32G内存.4个CPU,每个CPU 8核. 3.MySQL目 ...

  7. mysql 走索引 很慢_MySQL优化:为什么SQL走索引还那么慢?

    背景 2019-01-11 9:00-10:00 一个 MySQL 数据库把 CPU 打满了. 硬件配置:256G 内存,48 core 分析过程 接手这个问题时现场已经不在了,信息有限,所以我们先从 ...

  8. mysql 查看表是否存在_MySQL优化篇二

    单表优化 最佳左前缀原则为,保持索引的定义和使用顺序的一致性 将含In的范围查询,放到where条件语句的最后. 索引需要逐步优化 两表优化 小表驱动大表 避免索引失效的一些原则: 复合索引,不要跨列 ...

  9. mysql update 几万 非常慢_Mysql优化专题

    优化,一直是面试最常问的一个问题.因为从优化的角度,优化的思路,完全可以看出一个人的技术积累.那么,关于系统优化,假设这么个场景,用户反映系统太卡(其实就是高并发),那么我们怎么优化? 如果请求过多, ...

  10. mysql 走索引 很慢_MySQL 优化:为什么 SQL 走索引还那么慢?

    背景 2019-01-11 9:00-10:00 一个 MySQL 数据库把 CPU 打满了. 硬件配置:256G 内存,48 core 分析过程 接手这个问题时现场已经不在了,信息有限,所以我们先从 ...

最新文章

  1. 潘石屹首次Python考试成绩 99 分,失分点:画完图后忘了隐藏画笔的箭头
  2. checkVector()
  3. java socket程序_java 简单的java socket程序
  4. oracle复杂密码,如何配置 Oracle 11g 复杂密码校验设置
  5. CSS3学习笔记-技术提示
  6. 我正在运行哪个版本的PostgreSQL?
  7. windows “文件大小”与“占用空间”、文件系统与文件拷贝
  8. 【裴礼文数学分析】例1.1.5
  9. 【数据处理】——利用Excel VBA批量将详细地址转换成省市区三级行政区划
  10. 吐槽 intent:#Intent;S.K_1171477665=;end
  11. 嵌入式Linux:V3s移植NES游戏,声音,游戏手柄
  12. vuex的commit和dispatch
  13. C语言程序设计(2020)编程题答案——第14章结构体、共用体和用户定义类型
  14. Acwing-4818. 奶牛大学
  15. 微信小程序音频播放器(第二版)
  16. Win11系统注销在哪?Win11系统注销的方法
  17. beaglebone black下接nrf24l01与RFID标签的通信(基于EZSDK linux平台)
  18. 记录写博文用到的一些工具
  19. python手机销售系统_京东手机销售数据分析kaggle复盘python+tableau分析
  20. 东莞惠州楼盘又来深抢客 推盘量居历史高位 2012.5.12

热门文章

  1. laravel php artisan migrate 数据迁移时出现的[HY000][1045]错误
  2. shell脚本 空格
  3. PureLayout,使用纯代码写AutoLayout
  4. 【转】Nutch源代码研究 网页抓取 数据结构
  5. installanywhere's LAX Properties
  6. ORB_SLAM2之Pangolin的安装与问题处理
  7. python SQLite 初识
  8. 扇贝有道180919每日一句
  9. Atitit mysql存储过程编写指南 1. 定义变量 1 1.1. 变量名以@开头用户变量 会话变量 1 1.2. 以declare关键字声明 存储过程变量 2 1.3. @是用户自定义变量,
  10. Atitit 学校模式之 天堂模式 目录 1.1. 宗旨,让学生们乐不思蜀 打造人间天堂 2 2. 组织结构 2 2.1. 娱乐事业部 2 2.2. 文艺事业部 2 2.3. 三大金山挖掘(教育 医