转自 http://blog.csdn.net/tonyxf121/article/details/7796657

join的实现原理

join的实现是采用Nested Loop Join算法,就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果有多个join,则将前面的结果集作为循环数据,再一次作为循环条件到后一个表中查询数据。

接下来通过一个三表join查询来说明MySQL的Nested Loop Join的实现方式。

  1. select m.subject msg_subject, c.content msg_content
  2. from user_group g,group_message m,group_message_content c
  3. where g.user_id = 1
  4. and m.group_id = g.group_id
  5. and c.group_msg_id = m.id
 

使用explain看看执行计划:

  1. explain select m.subject msg_subject, c.content msg_content from user_group g,group_message m,
  2. group_message_content c where g.user_id = 1 and m.group_id = g.group_id and c.group_msg_id = m.id\G;

结果如下:

  1. *************************** 1. row ***************************
  2. id: 1
  3. select_type: SIMPLE
  4. table: g
  5. type: ref
  6. possible_keys: user_group_gid_ind,user_group_uid_ind,user_group_gid_uid_ind
  7. key: user_group_uid_ind
  8. key_len: 4
  9. ref: const
  10. rows: 2
  11. Extra:
  12. *************************** 2. row ***************************
  13. id: 1
  14. select_type: SIMPLE
  15. table: m
  16. type: ref
  17. possible_keys: PRIMARY,idx_group_message_gid_uid
  18. key: idx_group_message_gid_uid
  19. key_len: 4
  20. ref: g.group_id
  21. rows: 3
  22. Extra:
  23. *************************** 3. row ***************************
  24. id: 1
  25. select_type: SIMPLE
  26. table: c
  27. type: ref
  28. possible_keys: idx_group_message_content_msg_id
  29. key: idx_group_message_content_msg_id
  30. key_len: 4
  31. ref: m.id
  32. rows: 2
  33. Extra:

从结果可以看出,explain选择user_group作为驱动表,首先通过索引user_group_uid_ind来进行const条件的索引ref查找,然后用user_group表中过滤出来的结果集group_id字段作为查询条件,对group_message循环查询,然后再用过滤出来的结果集中的group_message的id作为条件与group_message_content的group_msg_id进行循环比较查询,获得最终的结果。

这个过程可以通过如下代码来表示:

for each record g_rec in table user_group that g_rec.user_id=1{
     for each record m_rec in group_message that m_rec.group_id=g_rec.group_id{
          for each record c_rec in group_message_content that c_rec.group_msg_id=m_rec.id
                pass the (g_rec.user_id, m_rec.subject, c_rec.content) row
          combination to output;
      }
}

如果去掉group_message_content表上面的group_msg_id字段的索引,执行计划会有所不一样。

  1. drop index idx_group_message_content_msg_id on group_message_content;
  2. explain select m.subject msg_subject, c.content msg_content from user_group g,group_message m,
  3. group_message_content c where g.user_id = 1 and m.group_id = g.group_id and c.group_msg_id = m.id\G;

得到的执行计划如下:

  1. *************************** 1. row ***************************
  2. id: 1
  3. select_type: SIMPLE
  4. table: g
  5. type: ref
  6. possible_keys: user_group_uid_ind
  7. key: user_group_uid_ind
  8. key_len: 4
  9. ref: const
  10. rows: 2
  11. Extra:
  12. *************************** 2. row ***************************
  13. id: 1
  14. select_type: SIMPLE
  15. table: m
  16. type: ref
  17. possible_keys: PRIMARY,idx_group_message_gid_uid
  18. key: idx_group_message_gid_uid
  19. key_len: 4
  20. ref: g.group_id
  21. rows: 3
  22. Extra:
  23. *************************** 3. row ***************************
  24. id: 1
  25. select_type: SIMPLE
  26. table: c
  27. type: ALL
  28. possible_keys: NULL
  29. key: NULL
  30. key_len: NULL
  31. ref: NULL
  32. rows: 96
  33. Extra:Using where;Using join buffer

因为删除了索引,所以group_message_content的访问从ref变成了ALL,keys相关的信息也变成了NULL,Extra信息也变成了Using Where和Using join buffer,也就是说需要获取content内容只能通过对全表的数据进行where过滤才能获取。Using join buffer是指使用到了Cache,只有当join类型为ALL,index,rang或者是index_merge的时候才会使用join buffer,它的使用过程可以用下面代码来表示:

for each record g_rec in table user_group{
      for each record m_rec in group_message that m_rec.group_id=g_rec.group_id{
           put (g_rec, m_rec) into the buffer
           if (buffer is full)
                 flush_buffer();
      }
}
flush_buffer(){
      for each record c_rec in group_message_content that c_rec.group_msg_id = c_rec.id{
            for each record in the buffer
                 pass (g_rec.user_id, m_rec.subject, c_rec.content) row combination to output;
      }
      empty the buffer;
}
在实现过程中可以看到把user_group和group_message的结果集放到join buffer中,而不用每次user_group和group_message关联后马上和group_message_content关联,这也是没有必要的;需要注意的是join buffer中只保留查询结果中出现的列值,它的大小不依赖于表的大小,我们在伪代码中看到当join buffer被填满后,mysql将会flush buffer。

join语句的优化

1. 用小结果集驱动大结果集,尽量减少join语句中的Nested Loop的循环总次数;

2. 优先优化Nested Loop的内层循环,因为内层循环是循环中执行次数最多的,每次循环提升很小的性能都能在整个循环中提升很大的性能;

3. 对被驱动表的join字段上建立索引;

4. 当被驱动表的join字段上无法建立索引的时候,设置足够的Join Buffer Size。

增加一点:

ON是最先执行, WHERE次之,HAVING最后,因为ON是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,WHERE也应该比 HAVING快点的,因为它过滤数据后才进行SUM,在两个表联接时才用ON的,所以在一个表的时候,就剩下WHERE跟HAVING比较了

1考虑联接优先顺序:

2INNER JOIN

3LEFT JOIN (注:RIGHT JOIN 用 LEFT JOIN 替代)

4CROSS JOIN

打包小工具

http://www.linuxidc.com/Linux/2014-03/98553.htm

1110Nested Loop Join算法的更多相关文章

  1. 1122MySQL性能优化之 Nested Loop Join和Block Nested-Loop Join(BNL)

    转自http://blog.itpub.net/22664653/viewspace-1692317/ 一 介绍  相信许多开发/DBA在使用MySQL的过程中,对于MySQL处理多表关联的方式或者说 ...

  2. 关于join算法的四篇文章

    MySQL Join算法与调优白皮书(一) MySQL Join算法与调优白皮书(二) MySQL Join算法与调优白皮书(三) MySQL Join算法与调优白皮书(四) MariaDB Join ...

  3. 44 答疑(三)--join的写法/Simple nested loop join的性能问题/Distinct和group by的性能/备库自增主键问题

    44 答疑(三) Join的写法 35节介绍了join执行顺序,加了straight_join,两个问题: --1 如果用left join,左边的表一定是驱动表吗 --2 如果两个表的join包含多 ...

  4. MySQL Nested-Loop Join算法学习

    不知不觉的玩了两年多的MySQL,发现很多人都说MySQL对比Oracle来说,优化器做的比较差,其实某种程度上来说确实是这样,但是毕竟MySQL才到5.7版本,Oracle都已经发展到12c了,今天 ...

  5. SQL Server的三种物理连接之Loop Join(一)

    Sql Server有三种物理连接Loop Join,Merge Join,Hash Join, 当表之间连接的时候会选择其中之一,不同的连接产生的性能不同,理解这三种物理连接对性能调优有很大帮助. ...

  6. 24.join算法/锁_1

    一. JOIN算法1.1. JOIN 语法 mysql> select * from t4; +---+------+ | a | b | +---+------+ | | 11 | | | 5 ...

  7. SQL Server nested loop join 效率试验

    从很多网页上都看到,SQL Server有三种Join的算法, nested loop join, merge join, hash join. 其中最常用的就是nested loop join. 在 ...

  8. Merge join、Hash join、Nested loop join对比分析

    简介 我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge Join,Hash Join ...

  9. 022:SQL优化--JOIN算法

    目录 一. SQL优化--JOIN算法 1.1. JOIN 写法对比 2. JOIN的成本 3. JOIN算法 3.1. simple nested loop join 3.2. index nest ...

随机推荐

  1. Android 的提权 (Root) 原理是什么?

    作者:Kevin链接:https://www.zhihu.com/question/21074979/answer/18176410来源:知乎著作权归作者所有,转载请联系作者获得授权. Android ...

  2. 磁盘配额-----quota

    为什么要使用磁盘配额:为了限制普通用户使用普通磁盘的空间与创建文件的个数等. 不至于个别人的浪费影响所有人的使用. 需要安装quota的软件包. mount -o usrquota,grpquota ...

  3. UESTC-第五届ACM趣味程序设计竞赛第四场(正式赛)--不完全解题报告

    比赛链接: http://acm.uestc.edu.cn/contest.php?cid=230 A.Police And The Thief ---UESTC 1913 简单博弈,先假设在警察先走 ...

  4. NOIP2003pj数字游戏[环形DP]

    题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分 ...

  5. 01 Hibernate错题分析

    解析: 此题目考查的是对Hibernate中交叉连接的理解.HQL支持SQL风格的交叉连接查询,交叉连接适用于两个类之间没有定义任何关联时.在where字句中,通过属性作为筛选条件,如统计报表数据.使 ...

  6. AC日记——字符替换 openjudge 1.7 08

    08:字符替换 总时间限制:  1000ms 内存限制:  65536kB 描述 把一个字符串中特定的字符全部用给定的字符替换,得到一个新的字符串. 输入 只有一行,由一个字符串和两个字符组成,中间用 ...

  7. Apache http Server 2.4 安装与配置

    前言 Apache官网从2.2之后,不再提供windows的msi或exe安装版本,现在Apache http Server有两个分支2.2及2.4 注意事项 如果之前有安装2.2的版本,请先卸载 A ...

  8. C#手工注入辅助工具

    看了某牛出版的MySql手注天书一神书,基本上解决了SQL注入上的知识点,于是打完(酱油)省赛回来通宵了一晚上写了个工具 方便语句构造SQL 联合查询 报错注入 盲注 读写 命令执行 基本都有整合 遇 ...

  9. js+JQuery实现返回顶部功能

    很多网站上都有返回顶部的效果,本文阐述如何使用jquery实现返回顶部按钮. 首先需要在顶部添加如下html元素: <p id="back-to-top"><a  ...

  10. PHPExcel

    1.PHPExcel类中读取Excel文件相关函数和使用方法 插件官网:http://phpexcel.codeplex.com/ <?php require_once 'Classes/PHP ...