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

第一篇: 单表的cost计算

数据结构:

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

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

  1. key_length:key的长度
  2. key_parts:key一共有多少个column
  3. key_part:key中具体的column
  4. 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)对象,包含了当前查询的所有组件和各种转换结果,其中 :

  1. prepare:进行一些等价交换之类的变化
  2. optimize:选择join的方式和access path
  3. exec:根据执行计划运行查询

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

cost的计算方法

cost = cpu cost + io cost

  1. cpu cost:server层对返回的记录数的compare时间
  2. io cost:引擎层根据扫描记录的记录数计算cost

统计信息

这里用到了两部分统计信息:
1. server层的统计信息,保存在table_share中。包括:

  1. key_length
  2. rec_per_key
  3. block_size等

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

  1. stat_n_rows
  2. stat_clustered_index_size
  3. 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扫描

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

转载于:https://www.cnblogs.com/xpchild/p/3770823.html

MySQL优化器cost计算相关推荐

  1. MySQL优化器如何预估查询成本

    MySQL有哪些查询成本 MySQL 执行一个查询可以有不同的执行方案.在我们开发过程中,所有写过的sql语句都会丢给MySQL端的优化器.由优化器判断并选择其中成本最低,或者说代价最低的那种方案去真 ...

  2. Mysql 优化器内部JOIN算法hash join On-Disk Hash Join Grace Hash Join Hybrid hash join过程详解

    Mysql 各种hash join算法讲解 hash join的概述 提到hash join之前自然得说Nest loop join,以两个表的关联为例,它其实是个双层循环,先遍历外层的表(n条),再 ...

  3. mysql not in优化_98%的人不知道的MySQL优化器原理

    ​| 作者 梁东阳,数据库研发中心数据库内核工程师,负责腾讯云MySQL的内核开发. 在日常运维中,相信不少人都收藏了很多关于查询优化的方法论和小技巧,但是仔细想想,你真的了解这些优化背后的原理吗? ...

  4. MySQL 优化器原来是这样工作的

    文章目录 优化器概述 逻辑转换 基于成本的优化 控制优化程度 设置成本常量 数据字典与统计信息 控制优化行为 优化器和索引提示 总结 大家好,我是只谈技术不剪发的 Tony 老师.我们在 MySQL ...

  5. MySQL优化器_MySQL查询优化器

    MySQL优化器 MySQL架构图 讲到MySQL,就绕不开他的架构图.MySQL是一个经典的C/S架构.服务器这边分两层:第一层是Server层,第二层是存储引擎.Server层处理主要的业务操作流 ...

  6. MySQL优化器:index merge介绍

    在MySQL官方手册上,关于index merge的介绍非常非常少.甚至还有不少误导的地方,这次把5.1版本关于此类优化处理的代码细看了一遍,以案例的方式介绍了各种实用index merge访问类型的 ...

  7. MySQL优化器选错索引情况

    MySQL优化器选错索引情况 1. 优化器选错索引 2. 优化器的逻辑 3. 索引选择异常和处理 1. 优化器选错索引 之前MySQL架构以及执行sql查询语句介绍过MySQL优化器可以帮助我们优化s ...

  8. mysql优化器怎么选择索引,为什么MySQL查询优化器会选择聚集主索引上的二级索引?...

    为什么Mysql优化器在执行'select * from lookup'而没有order by子句时选择二级索引. 它只是一个侥幸,或者这是一个幕后优化,假设你添加了一个二级索引,它比主键更重要. 我 ...

  9. mysql优化器放弃索引场景,MYSQL索引优化(索引失效场景)

    学习mysql是作为一名Java工程师必不可少的事情,但是我们只认识mysql的增删查改建表等等的sql语句其实远远不够的,对于进阶mysql来说,索引是一个很重要的部分.下面我们就来说一下在mysq ...

最新文章

  1. Ubuntu在命令行下不能够切换字母的大小写,只能输入大写字母
  2. android SharedPreferences数据存储
  3. svm学习之线性部分总结
  4. 用python做逻辑回归梯度上升_机器学习实例---4.1、Logistic回归基础篇之梯度上升算法...
  5. oracle数据库主键自增序列_oracle数据库ID自增长--序列
  6. 算法总结 -- 博弈论(PN图)
  7. 命运(HDU 2571 简单动态规划)
  8. OneNote使用技巧及运用
  9. vector容器,容量和大小的操作
  10. libIconv.lib编码库的生成和使用
  11. 技术与教研并驾齐驱,海风教育如何用模式创新定义教育智能新高度?
  12. 逆向PPTV视频真实播放地址全过程(Java版)
  13. PS钢笔--制图抠图
  14. Word标题跟随正文样式缩进的解决办法
  15. laragon集成环境使用,跑起laravel项目
  16. 如何使用 Axios 中的请求拦截器 和响应拦截器
  17. 天载配资总结指数很健康,现在新高
  18. 考虑碳交易机制的园区综合能源系统电热协同运行优化研究(Matlab代码实现)
  19. GCM 的升级版——FCM(firebase cloud messaging)
  20. 实现全托管,腾讯云服务网格的架构演进

热门文章

  1. js获取select选中的内容
  2. WPF Binding
  3. eclipse自动补全的设置
  4. 让 .NET 程序 Autorun
  5. [Java]Annotation元数据的几个应用
  6. (十)如何查找端口被那个程序占用
  7. volley imagerequest
  8. 中医药专家开年会 推荐11种最靠谱的抗癌食物
  9. mysql可以运行在不同sql mode模式下面,sql mode模式定义了mysql应该支持的sql语法,数据校验等...
  10. JavaScript instanceof的实现