总的来说,mysql认为任何一个查询都是一次关联,并不仅仅是一个查询需要用到两个表匹配才叫关联,所以,在mysql中,每一个查询,每一个片段(包括子查询,甚至单表select)都可能是关联。所以,理解mysql如何执行关联查询至关重要,先来看一个union的例子,对于union,mysql先将一系列的单个查询结果放到一个临时表中,然后再重新读出临时表数据来完成union,在mysql的概念中,每个查询都是一次关联,所以读取结果临时表也是一次关联。

当前mysql关联执行的策略很简单,mysql对任何关联都执行嵌套循环关联操作,即,mysql先在一个表中循环读取单条数据,然后再嵌套循环到下一个表中寻找匹配的行,依次下去,直到找到所有表中匹配的行为止。然后根据各个表匹配的行,返回查询中需要的各个列,mysql会尝试在最后一个关联表中找到所有匹配的行,如果最后一个关联表无法找到更多的行以后,mysql返回到上一层次关联表,看是否能够找到更多的匹配记录,依次类推迭代执行。照这样的方法查找第一个表记录,再嵌套查询下一个关联表,然后回溯到上一个表,在mysql中是通过嵌套循环的方式实现(正如其名:嵌套循环关联)

从本质上说,mysql对所有的类型的查询都以同样的方式运行,如:mysql在from子句中遇到子查询,先执行子查询并将结果放到一个临时表中,然后将这个临时表当作一个普通表对待(正如其名:派生表),mysql在执行union查询时也使用类似的临时表,在遇到右外连接是,mysql将其改写成等价的左外连接,换而言之,当前版本的mysql会将所有的查询类型都换换成类似的执行计划,不过,不是所有的查询都可以转换成上面的形式,如:全外连接就无法通过嵌套循环和回溯的方式完成,这也是mysql并不支持全外连接的原因。

注意:mysql临时表没有任何索引,在编写复杂的子查询和关联查询的时候需要注意这一点,这一点对union查询也一样,在mysql5.6和mariadb中有了重大改变,这两个版本都引入了更加复杂的执行计划。

执行计划:

和很多其他关系数据库不同,mysql并不会生成查询字节码来执行查询,mysql生成查询的一棵指令树,然后通过存储引擎执行完成这棵指令树并返回结果,最终的执行计划包含了重构查询的全部信息,如对某个查询执行explain extended后,再执行show warnings,就可以查看到重构的查询。 mysql总是从一个表开始一直嵌套循环,回溯完成所有表的关联。所以,mysql的执行计划是一棵左侧深度优先的树,然后回溯到上一层关联:

关联查询优化器:

mysql优化器最重要的一部分就是关联查询优化,它决定了多个表关联时的顺序,通常多表关联的时候,可以有多种不同的关联顺序来获得相同的执行效果,关联查询优化器则通过评估不同顺序时的成本来选择一个代价最小的关联顺序。

示例:

explain select film.film_id,film.title,film.release_year,actor.actor_id,actor.first_name,actor.last_name from sakila.film join sakila.film_actor using(film_id) join sakila.actor using(actor_id)\G;

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

table: actor

type: ALL

possible_keys: PRIMARY

key: NULL

key_len: NULL

ref: NULL

rows: 200

Extra: NULL

*************************** 2. row ***************************

id: 1

select_type: SIMPLE

table: film_actor

type: ref

possible_keys: PRIMARY,idx_fk_film_id

key: PRIMARY

key_len: 2

ref: sakila.actor.actor_id

rows: 13

Extra: Using index

*************************** 3. row ***************************

id: 1

select_type: SIMPLE

table: film

type: eq_ref

possible_keys: PRIMARY

key: PRIMARY

key_len: 2

ref: sakila.film_actor.film_id

rows: 1

Extra: NULL

3 rows in set (0.00 sec)

执行计划中可以看到,mysql从actor表开始,使用film_actor表的索引film_id来查找对应的actor_id值,然后根据film表的主键找到对应的记录,oracle用户会用下面的术语描述:actor表作为驱动表先找到file_actor表,然后以此结果为驱动表再查找film表。

下面使用straight_join关键字指定关联表顺序,如下:

explain select straight_join film.film_id,film.title,film.release_year,actor.actor_id,actor.first_name,actor.last_name from sakila.film join sakila.film_actor using(film_id) join sakila.actor using(actor_id)\G;

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

table: film

type: ALL

possible_keys: PRIMARY

key: NULL

key_len: NULL

ref: NULL

rows: 1000

Extra: NULL

*************************** 2. row ***************************

id: 1

select_type: SIMPLE

table: film_actor

type: ref

possible_keys: PRIMARY,idx_fk_film_id

key: idx_fk_film_id

key_len: 2

ref: sakila.film.film_id

rows: 2

Extra: Using index

*************************** 3. row ***************************

id: 1

select_type: SIMPLE

table: actor

type: eq_ref

possible_keys: PRIMARY

key: PRIMARY

key_len: 2

ref: sakila.film_actor.actor_id

rows: 1

Extra: NULL

3 rows in set (0.00 sec)

从上面的explain结果上看,mysql自动选择的关联顺序与使用straight_join关键字的关联顺序完全倒转过来,从上面的对比结果上可以看出,mysql把关联表倒转过来后,film只扫描一行,而film在最前时扫描行数是1000.

如果mysql选择首先扫描actor表,只会返回200条记录进行后面的嵌套循环查询,即,倒转关联顺序会让查询进行更少的嵌套循环和回溯操作,为了验证优化器的选择是否正确,我们单独执行了这两个查询,并且看last_query_cost状态值(这里我使用的虚拟机做测试),结果mysql选择的顺序预估成本为3883.340463,而我们手工指定的顺序预估成本为4012.731064。

这个简单的示例说明mysql是如何选项合适的关联顺序来让查询执行的成本尽可能低,重新定义关联的顺序是优化器非常重要的一部分,不过有时候,优化器给出的并不是最优的关联顺序,这时可以使    用straight_join关键字重写查询,让优化器按照你认为的最优的关联顺序执行,不过,人的判断很难那么精准,所以大部分时候,优化器做出的选择比普通人判断的要更精准。

关联优化器会尝试在所有的关联顺序中选择一个成本最小的来生成执行计划树,如果可能,优化器会遍历每一个表后逐个做嵌套循环计算每一颗可能的执行计划树的成本,最后返回一个最优的执行计划。

但是,糟糕的是,如果有超过n个表关联,那么需要检查n的阶乘种关联顺序,我们称之为所有可能的执行计划的“搜索空间”,搜索空间的增长速度非常快,如:若是10个关联,那么共有3628800种关联顺序,当搜索空间非常大的时候,优化器不可能逐一评估每一种关联顺序的成本,这时,优化器选择使用贪婪搜索的方式查找最优的关联顺序,实际上,当需要关联的表超过optimizer_search_depth的限制的时候,就会选择贪婪搜索模式了,optimizer_search_depth这个参数可以根据需要动态指定大小,默认为62。

 

MySQL如何关联查询的更多相关文章

  1. mysql(一) 关联查询的方式

    mysql做关联查询时,一般使用join....on.....的语法. 但还有其它两种语法形式,三者的主要区别在于书写形式,其余方面并无太多差异. 如下三种形式: select * from trad ...

  2. MySQL 查询优化 - 关联查询

    1. 关联查询执行流程 MySQL执行关联查询的策略很简单,他会从一个表中循环取出单条数据,然后用该条数据到下一个表中寻找匹配的行,然后回溯到上一个表,到所有的数据匹配完成为止.因此也被称为" ...

  3. 【mysql】关联查询_子查询_排序分组优化

    1. 关联查询优化 1.1 left join 结论: ①在优化关联查询时,只有在被驱动表上建立索引才有效! ②left join 时,左侧的为驱动表,右侧为被驱动表! 1.2 inner join ...

  4. MySQL 自关联查询

    定义表areas,结构如下 id atitle pid 因为省没有所属的省份,所以可以填写为null 城市所属的省份pid,填写省所对应的编号id 这就是自关联,表中的某一列,关联了这个表中的另外一列 ...

  5. Yii2实现跨mysql数据库关联查询排序功能

    遇到一个项目,需要跨表网上找了很多的资料,整理一下,方便以后再次使用 背景:在一个mysql服务器上(注意:两个数据库必须在同一个mysql服务器上)有两个数据库: memory (存储常规数据表) ...

  6. mysql的关联查询简写

    平常的内连接查询: SELECT * from ab_style as a INNER JOIN ab_url as b on a.style_bold=b.url_id 可支持简写风格: selec ...

  7. mysql 表关联查询报错 ERROR 1267 (HY000)

    解决翻案:http://stackoverflow.com/questions/1008287/illegal-mix-of-collations-mysql-error 即: SET collati ...

  8. MySQL执行一个查询的过程

    总体流程 客户端发送一条查询给服务器: 服务器先会检查查询缓存,如果命中了缓存,则立即返回存储在缓存中的结果.否则进入下一阶段: 服务器端进行SQL解析.预处理,再由优化器生成对应的执行计划: MyS ...

  9. JDBC MySQL 多表关联查询查询

    public static void main(String[] args) throws Exception{ Class.forName("com.mysql.jdbc.Driver&q ...

随机推荐

  1. js == 判断

    根据阮一峰介绍的算法文章分12部分可判断: 如果x不是正常值(比如抛出一个错误),中断执行. 如果y不是正常值,中断执行. 如果Type(x)与Type(y)相同,执行严格相等运算x === y. 如 ...

  2. EditText中输入手机号码时,自动添加空格

    输入手机号码时,自动添加空格,更容易辨别 public class PhoneWatcher implements TextWatcher { private EditText _text; publ ...

  3. PHP获取远程网站的服务器时间

    <?php function get_time($server){ $data  = "HEAD / HTTP/1.1\r\n"; $data .= "Host:  ...

  4. vba 工作案例-sheet间拷贝内容

    核心代码就是Copy Destination. Sub copy_data() ' ' copy_data 宏 ' ' Dim fzjgs() As Variant Dim cities As Var ...

  5. 【ionic】Mac IOS下真机调试

    模拟调试不能保证真机一定没问题,所以真机调试是非常必要的一步 IOS设备 启用设备调试 在IOS设备中(Iphone,Ipad)中开始web检测器 设备->safari->高级->w ...

  6. Linux内核设计第一周 ——从汇编语言出发理解计算机工作原理

    Linux内核设计第一周 ——从汇编语言出发理解计算机工作原理 作者:宋宸宁(20135315) 一.实验过程 图1 编写songchenning5315.c文件 图2 将c文件汇编成32位机器语言 ...

  7. easyUI loyout tabs自适应宽度

    index.html 页面 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http ...

  8. ASP.NET Page执行顺序【转】

    一.ASP.NET 母版页和内容页中的事件 母版页和内容页都可以包含控件的事件处理程序.对于控件而言,事件是在本地处理的,即内容页中的控件在内容页中引发事件,母版页中的控件在母版页中引发事件.控件事件 ...

  9. java 向上转型 向下转型

    //父类 四边形 class Quadrangle{ public static void draw (Quadrangle q){ } } //子类  public class Parallelog ...

  10. html5新增语义标签

    1.header <header> 标签定义文档的页眉(介绍信息). 2.nav <nav> 标签定义导航链接的部分. 3.article <article> 标签 ...