mysql如何执行关联查询与优化

一、前言

  在数据库中执行查询(select)在我们工作中是非常常见的,工作中离不开CRUD,在执行查询(select)时,多表关联也非常常见,我们用的也比较多,那么mysql内部是如何执行关联查询的呢?它又做了哪些优化呢?今天我们就来揭开mysql关联查询的神秘面纱。

二、mysql如何执行关联查询

  mysql关联执行的策略很简单:mysql对任何关联都执行嵌套循环关联操作。即:mysql先在一个表中循环取出单条数据,然后再嵌套循环到下一个表中寻找匹配的行,依次下去,直到找到所有表中匹配的行为止。然后根据各个表匹配的行,返回查询中需要的各个列。如果mysql在最后一个关联表无法找到更多的行,它将返回上一层关联表,看看能否找到更多的匹配记录,以此类推迭代执行。

  按照这种方式,mysql查找第一个表的记录,再嵌套查询下一个关联表,然后回溯到上一个表,这正如其名——“嵌套循环关联”。看一下下面的例子:

SELECT
t1.column1,
t2.column2
FROM
tb1 t1
INNER JOIN tb2 t2 ON t1.column3 = t2.column3
WHERE
t1.column1 IN (4, 6)

  假设mysql按照查询中的表顺序进行关联操作,我们可以用伪代码表示其过程:

outer_iter = iterator over t1 WHERE    column3 IN (4, 6)
outer_row = outer_iter.next
WHILE outer_row
inner_iter = iterator over t2 WHERE column3 = outer_row.column3
inner_row = inner_iter.next
WHILE inner_row
output [ outer_row.column1,inner_row.column2 ]
inner_row = inner_iter.next
END
outer_row = outer_iter.next
END

  上面的执行过程对于单表查询和多表关联查询都适用,如果只是单表查询,那么只需要完成最外层的循环操作即可。如果关联中存在外连接,上面的过程仍然适用,我们只需略作修改。查询sql如下:

SELECT
t1.column1,
t2.column2
FROM
tb1 t1
LEFT OUTER JOIN tb2 t2 ON t1.column3 = t2.column3
WHERE
t1.column1 IN (4, 6)

  对应的伪代码修改如下:

outer_iter = iterator over t1 WHERE    column3 IN (4, 6)
outer_row = outer_iter.next
WHILE outer_row
inner_iter = iterator over t2 WHERE column3 = outer_row.column3
inner_row = inner_iter.next
IF inner_row
WHILE inner_row
output [ outer_row.column1,inner_row.column2 ]
inner_row = inner_iter.next
END
ELSE
output [ outer_row.column1,NULL ]
END

outer_row = outer_iter.next
END

  如果用图表示关联查询的过程,图示如下,请从左至右,从上至下看这幅图:

t1 t2 结果行
column1=4,column3=1 column3=1,column2=1 column1=4,column3=1
  column3=1,column2=2 column1=4,column3=2
  column3=1,column2=3 column1=4,column3=3
column1=6,column3=2 column3=2,column2=1 column1=6,column3=1
  column3=2,column2=2 column1=6,column3=2
  column3=2,column2=3 column1=6,column3=3

  mysql的关联方式也可以由一棵树表示,它是一个左侧深度优先树:
                              

三、关联查询优化器

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

  大家看一下下面的查询,它可以通过不同的关联顺序得到相同的结果:

SELECT
u.realname,
u.mobile,
c.`name`
FROM
USER u
INNER JOIN user_company uc ON u.id = uc.user_id
INNER JOIN company c ON uc.company_id = c.id

  按照上面的关联执行规则,我们可以给出执行计划,mysql可以从user表开始,通过user_company表的user_id列找到对应的company_id,然后再通过company表的主键找到对应的记录。我们执行了mysql的explain,得出的结果如下:

          

  这和我们给出的执行顺序不一致,这样的效率是否更高呢?我们使用STRAIGHT_JOIN关键字得出的分析结果如下:

          

  我们分析一下mysql为什么会改变关联的顺序,我们可以看到改变顺序后,第一个关联表只需要扫描很少的行数,第二个、第三个关联表的扫描项也是不同的。uc表只有480条记录,而u表有2300条记录。如果先扫描uc表,只返回480条记录,然后进行嵌套循环查询,如果先扫描u表,则返回2300条记录。换句话说,更改顺序后,查询可以进行更少的嵌套循环和回溯操作。

  通过这个例子,我们可以看到mysql是如何选择合适的顺序让查询执行的成本更低的。重新定义关联顺序是优化器的一个重要的功能,它尝试在所有关联顺序中选择一个成本最小的来生成执行计划树。

  至此,mysql是如何进行关联查询的,以及优化,已经介绍完了,欢迎大家多多交流。

mysql如何执行关联查询与优化的更多相关文章

  1. MySQL如何执行关联查询

    MySQL中‘关联(join)’ 一词包含的意义比一般意义上理解的要更广泛.总的来说,MySQL认为任何一个查询都是一次‘关联’ --并不仅仅是一个查询需要到两个表的匹配才叫关联,索引在MySQL中, ...

  2. MySQL 如何执行关联查询

    本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/51 当前mysql执行的策略很简单:mysql对任何关联都执行嵌 ...

  3. MySQL/MariaDB数据库的查询缓存优化

    MySQL/MariaDB数据库的查询缓存优化 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MySQL架构 Connectors(MySQL对外提供的交互接口,API): ...

  4. Mysql多表表关联查询 inner Join left join right join

    Mysql多表表关联查询 inner Join left join right join

  5. 高性能mysql 第六章查询性能优化 总结(上)查询的执行过程

    6  查询性能优化 6.1为什么查询会变慢 这里说明了的查询执行周期,从客户端到服务器端,服务器端解析,优化器生成执行计划,执行(可以细分,大体过程可以通过show profile查看),从服务器端返 ...

  6. 【MySQL】MySQL的执行计划及索引优化

    我们知道一般图书馆都会建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左右性能开始逐渐下降,虽然官方文档说500~800w记录,所以大数据量建立索引是非常有必要的. ...

  7. 高性能mysql 第6章 查询性能优化

    查询缓存: 在解析一个sql之前,如果查询缓存是打开的,mysql会去检查这个查询(根据sql的hash作为key)是否存在缓存中,如果命中的话,那么这个sql将会在解析,生成执行计划之前返回结果. ...

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

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

  9. mysql索引原理及查询速度优化

    一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句 ...

随机推荐

  1. 掌握sklearn系列——1 学会加载数据

    我们直接看代码: from sklearn import datasets #读取三组数据,前两个用于分类,第三个用于回归 iris = datasets.load_iris() digits = d ...

  2. 页面输入的数据格式转换类:BaseAction(经常使用于Struts框架中)

    在我们接收页面传来的数据时,这些数据都是以String类型接收的,所以要进行数据格式转换,这时候就能够统一为它们进行转换,并且在处理这些数据的类中能够继承ActionSupport类,然后让每个接收数 ...

  3. Maven实战(九)——打包的技巧

    "打包"这个词听起来比較土.比較正式的说法应该是"构建项目软件包".详细说就是将项目中的各种文件,比方源代码.编译生成的字节码.配置文件.文档,依照规范的格式生 ...

  4. jQuery遮罩层插件

    在网页上常常遇到须要等待非常久的操作,比方导出报表等.为了预防用户点击其它操作或者多次点击同个功能,须要用遮罩层把页面或者操作区盖住.防止用户进行下一步操作.同一时候能够提高界面友好度,让用户知道操作 ...

  5. 解决PL/SQL Developer 连接oracle 11g 64位中的问题

    1.错误1:Initialization error could not initialize 电脑上原本就装有oracle 11g 64位,但是PL/SQL却怎么也连接不上,报出" Ini ...

  6. OS X第三方类库管理工具cocoapods入门

    一.简介 什么是cocoapods?--是OS X和iOS下一个第三方类库管理工具.通过cocoapods,可以为项目添加"Pods"依赖库,并且管理其版本. cocoapods好 ...

  7. java开发收藏

    一.java工具 1.jenkins 项目集成工具 2.launch4j java打包成exe工具 二.json库 1.jsoniter 比以下都快 2.dsljson 3.fastjson 4.gs ...

  8. 移动浏览器H5页面通过scheme打开本地应用

    在移动端浏览器H5页面中,点击按钮打开本地应用主要通过 scheme 协议.本文主要介绍如何在浏览器H5页面中通过 scheme 协议打开本地应用. scheme协议定义 scheme 是一种页面之间 ...

  9. DotNetCasClient 如何获取Cas服务器返回的attributes中的数据

    最近开始接触做与其它认证系统的集成,其中有个是与某学校的CAS服务器集成.cas服务器认证成功后返回的数据格式如下: 其中红色部分是我需要取出来用于识别用户身份的数据. 一开始,我根据网上的教程,引用 ...

  10. 子查询。ANY三种用法。ALL两种用法。HAVING中使用子查询。SELECT中使用子查询。

    子查询存在的意义是解决多表查询带来的性能问题. 子查询返回单行多列: ANY三种用法: ALL两种用法: HAVING中的子查询返回单行单列: SELECT中使用子查询:(了解就好,避免使用这种方法! ...