前一篇介绍了cost的计算方法,下面测试一下两表关联的查询:

测试用例

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 CREATE TABLE `xpchild_1` (
`xxid` bigint(20) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
KEY `xpchild_1_id` (`xxid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

测试sql

select * from xpchild, xpchild_1 where xpchild.id=100 and xpchild.id=xpchild_1.xxid;

函数调用栈:
JOIN::optimize
   make_join_statistics
       update_ref_and_keys
       get_quick_record_count
       choose_plan

以上省略了JOIN::prepare的过程,prepare主要进行一些等级变化,上面的sql是一个比较简单的两表关联,并不会进行过多的变换。

step1: 初始化

make_join_statistics:
    根据select_lex->leaf_tables初始化每个JOIN_TAB对象,至此,一个sql对于一个join,对应两个join_tab.
    初始化quick_condition_rows为innodb中的stat统计信息中的record记录数。

step 2: 查询可用索引

update_ref_and_keys:根据where条件,选择可以使用的索引,加入到possible keys中,本例子加入的keys包括:
    xpchild: primary,xpchild_id_c1
    xpchild_1: xxid

(gdb) p *keyuse_array
$67 = {
buffer = 0x8ca1fb58 "@24214",
elements = 3,
max_element = 20,
alloc_increment = 64,
size_of_element = 48

step 3: 计算cost

get_quick_record_count:根据可选择的possible_keys计算cost。

1. xpchild表

因为有可以使用的primary,xpchild表s->type == JT_CONST,所以cost的计算为:

    s->found_records=s->records=s->read_time=1。
所以,mysql对于使用primary,unique key的使用上比较有倾向性,而且可以节省大量的计算cost的时间。

2. xpchild_1表:

全表扫描的records && read_time是:
  s->found_records= 1215
  s->read_time= 5

计算xxid索引的cost:
  get_quick_record_count
    test_quick_select:
      最终计算的cost:
        estimated_records=1
        best_read_time=2.21
  具体的计算方式,可以参考前面一篇博客

到此:xpchild的JOIN_TAB结构中,比较简单,const table类型,cost=1;
xpchild_1的JOIN_TAB结构中,found_records=1, read_time=2.21;
对于单表的的查询access path已经是最优的。

step 4:join的顺序:

choose_join:

1. 如果是const table;不再进行join顺序的计算,直接选择使用当前positions。
   memcpy((uchar*) join->best_positions,(uchar*) join->positions,sizeof(POSITION)*join->const_tables);
   join->best_read=1.0;

2. 为非const table,选择最优的访问顺序
    optimizer_search_depth:优化访问表join顺序的递归计算深度。
        straight_join:按照sql的顺序,或者添加sql hint确定的顺序,默认不使用
        greedy_search:贪婪算法,对于当前的查询,在候选的表中,选择一个最小cost添加到当前的plan中,递归完成。
            best_extension_by_limited_search:根据current_record_count,与调用best_access_path得到的best_record_count进行比较,选择最优的路径。
                best_access_path:table->quick_rows根据前面计算的records,得出cost,得到join->positions[idx]的最优路径。

join顺序选择的步骤:

1. 根据best_extension_by_limited_search在remaining table中选择cost最小的那个,本例中,xpchild的cost为:records=1 , read_time=0。所以选择为第一张表。

2. 然后从候选表中选择一个(只剩下xpchild_1表)加入到join的顺序中,并根据best_access_path选择一个cost最低的执行计划加入到plan中,这里选择xpchild_1_id的索引。

最后得到best plan,并赋值给last_query_cost;
    join->thd->status_var.last_query_cost= join->best_read;

最后得到的best plan:
(gdb) p tab->join->best_read
$73 = 1.1990000000000001

(gdb) p tab->join->best_positions
$72 = {{
records_read = 1,
read_time = 0,
table = 0x8ca06078, 'xpchild'
key = 0x8ca1fb58, 'primary'
ref_depend_map = 0
}, {
records_read = 1,
read_time = 1,
table = 0x8ca0620c, 'xpchild_1'
key = 0x8ca1fbb8, 'xpchild_1_id'
ref_depend_map = 0
}

未完待续:

MySQL优化器join顺序的更多相关文章

  1. 0104探究MySQL优化器对索引和JOIN顺序的选择

    转自http://www.jb51.net/article/67007.htm,感谢博主 本文通过一个案例来看看MySQL优化器如何选择索引和JOIN顺序.表结构和数据准备参考本文最后部分" ...

  2. 机智的MySQL优化器 --- is null

    [介绍] 工作的越久越到的的问题越多,就越是觉得一些“老话”历久弥新:由于最近的学习计划是深入的学习一遍MySQL优化器:学习过程中的一些成果 也会发布到这里,一来是为了整理自己已经知道的和新学到的, ...

  3. 如何干涉MySQL优化器使用hash join

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. GreatSQL是MySQL的国产分支版本,使用上与MySQL一致. 前言 实验 总结 前言 数据库的优化器相当于人类的大 ...

  4. 数据库 mysql 优化器原理

    MySQL查询优化器有几个目标,但是其中最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行. 你的最终目标是提交SELECT语句查找数据行,而不是排除数据行.优化器试图排除数据 ...

  5. MySQL优化器cost计算

    记录MySQL 5.5上,优化器进行cost计算的方法. 第一篇: 单表的cost计算 数据结构: 1. table_share: 包含了表的元数据,其中索引部分: key_info:一个key的结构 ...

  6. MySQL优化器功能开关optimizer_switch

    MySQL 8.0新增特性 use_invisible_indexes:是否使用不可见索引,MySQL 8.0新增可以创建invisible索引,这一开关控制优化器是否使用invisible索引,on ...

  7. MySQL优化器不使用索引的情况

    优化器选择不适用索引的情况 有时候,有乎其并没有选择索引而去查找数据,而是通过扫描聚集索引,也就是直接进行全表的扫描来得到数据.这种情况多发生于范围查找.JOIN链接操作等情况.例如 ; 通过SHOW ...

  8. MySQL优化器 --- index_merge

    [背景] 对于关系数据库中的一张表,通常来说数据页面的总大小要比较某一个索引占用的页面要大的多(上面说的索引是不包涵主键索引的); 更进一步我们可以推导出,如果我们通过读索引就能解决问题,那么它相比读 ...

  9. 《Mysql - 优化器是如何选择索引的?》

    一:概念 - 在 索引建立之后,一条语句可能会命中多个索引,这时,索引的选择,就会交由 优化器 来选择合适的索引. - 优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句. 二: ...

随机推荐

  1. 20151213Jquery学习笔记--插件

    插件(Plugin)也成为 jQuery 扩展(Extension),是一种遵循一定规范的应用程序接口编 写出来的程序.目前 jQuery 插件已超过几千种,由来自世界各地的开发者共同编写.验证 和完 ...

  2. js 函数命名

    1 函数命名可以使用匿名: var f=function(x){return x*2;} 2 可以使用变量: function double(x){return x*2;} 二者区别:后者会绑定到与其 ...

  3. jfinal不能正确加载html网页,总是报错的解决方法

    今天自学jfinal,遇到一个很奇怪的问题,render("/index.html");总是报错. 仔细看错误日志,才发现原来是因为html网页放到了WEB-INF文件夹下面了,所 ...

  4. com和dll(一)

    1.com为一种规范,使不同语言能在二进制层面上进行交互. 2.dll为ms的一种程序打包文件,使程序的代码能分开打包编译,并能在运行时共享.

  5. 第一个wxWidgets程序

    wxWidgets的安装方法网上有一大堆,可以参照http://wiki.codeblocks.org/index.php?title=WxWindowsQuickRef 这里解压并编译 ,也可以参照 ...

  6. scala - 从合并两个Map说开去 - foldLeft 和 foldRight 还有模式匹配

    开发中遇到需求:合并两个Map集合对象(将两个对应KEY的值累加) 先说解决方案: ( map1 )) ) } 这特么什么鬼  (╯‵□′)╯""┻━┻☆))>○<)  ...

  7. windows平台 culture name 详细列表

    点击打开链接http://msdn.microsoft.com/zh-cn/goglobal/bb896001.aspx LCID Culture Identifier Culture Name Lo ...

  8. react native学习1-安装,执行

    demo地址 http://www.oschina.net/p/reactnative http://my.oschina.net/luyongfugx/blog/394427#OSC_h1_1 翻译 ...

  9. 简简单单制作鼠标静态动态 ani cur 小结 鼠标形状指针

    近日在网上看到一个视频录制软件里的鼠标样子的指针感觉蛮好的自己制作了一个,效果还不错,几乎跟那个鼠标形状一模一样啦.总结了下制作过程现分享如下:1.首先用ps建立一个30*30像素的空白图片 然后将自 ...

  10. ObjectCopy

    对象的传参用的是传引用,但开发中通常不允许对传入参数进行修改.因此对象拷贝很常用,Python提供一个很方便的对象拷贝方法 如代码: __author__ = 'mengxuan' import co ...