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. Python2/3中的urllib库

    urllib库对照速查表 Python2.X Python3.X urllib urllib.request, urllib.error, urllib.parse urllib2 urllib.re ...

  2. java学习笔记之String类

    String类总结 String类概述: java.lang.String 类是字符串操作类 String类的常用构造方法: //1.直接赋值 String str= "hellojava& ...

  3. admin密码重置方式

    1.在项目根目录下运行:python manage.py shell 2.重设密码 from django.contrib.auth.models import User user =User.obj ...

  4. Linux安装Nginx以及简单理解

    1.Nginx简单介绍 ①.Nginx:一个高性能的HTTP和反向代理服务器,高并发处理很不错. ②.反向代理:在计算机世界里,由于单个服务器的处理客户端(用户)请求能力有一个极限,当用户的接入请求蜂 ...

  5. Comparable和Comparator的差别

    原文地址:http://leihuang.org/2014/11/16/Comparable-Vs-Comparator/ Comparable和Comparator都是用来实现集合中元素的比較.排序 ...

  6. 报表开发之扩展GROUP BY

    在实际运用中.比方在数据仓库中,常常须要对数据进行多维分析.不仅须要标准分组的结果(相当于 GROUP BY),还须要不同维度的小计(简单 GROUP BY 中取部分列分组)和合计(不分组).从而 提 ...

  7. IDEA下Spring Boot的快速搭建

    下边使用的是IDEA快速搭建一个Spring Boot项目 (1)File--New-New Project (2)点击Next填写相应的信息 (3)点击Next,选择Dependencies,这里创 ...

  8. Liunx的常用命令

    常用指令 ls 显示文件或目录 -l 列出文件详细信息l(list) -a 列出当前目录下所有文件及目录,包括隐藏的a(all) mkdir 创建目录 -p 创建目录,若无父目录,则创建p(paren ...

  9. License友好的前端组件合集

    在做Web开发过程中,不可避免的会用到各种UI组件.通常,我们并不会需要什么组件,都去自己开发的,网上有那么多好用的,我们为什么要自己造轮子呢?我通常只会在网上找不到合适的组件时,才会去自己开发一套. ...

  10. KendoUI 基础:Grid 绑定template展示

    Grid 绑定template展示 <div id="TodayEditorGrid" style="margin:0 10px"></div ...