1110Nested Loop Join算法

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

join的实现原理

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

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

[sql] view plain copy

  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看看执行计划:

[sql] view plain copy

  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;

结果如下:

[plain] view plain copy

  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字段的索引,执行计划会有所不一样。

[sql] view plain copy

  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;

得到的执行计划如下:

[plain] view plain copy

  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。

打包小工具

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

时间: 2024-11-08 20:17:21

1110Nested Loop Join算法的相关文章

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

转自http://blog.itpub.net/22664653/viewspace-1692317/ 一 介绍  相信许多开发/DBA在使用MySQL的过程中,对于MySQL处理多表关联的方式或者说性能一直不太满意.对于开发提交的含有join的查询,一般比较抗拒,从而建议将join拆分,避免join可能带来的性能问题,同时也增加了程序和DB的网络交互.5.5 版本之前,MySQL本身只支持一种表间关联方式,就是嵌套循环(Nested Loop).如果关联表的数据量很大,则join关联的执行时间

join中级篇---------hash join & merge join & nested loop Join

嵌套循环连接(Nested Loop Join) 循环嵌套连接是最基本的连接,正如其名所示那样,需要进行循环嵌套,嵌套循环是三种方式中唯一支持不等式连接的方式,这种连接方式的过程可以简单的用下图展示: 图1.循环嵌套连接的第一步 图2.循环嵌套连接的第二步 由上面两个图不难看出,循环嵌套连接查找内部循环表的次数等于外部循环的行数,当外部循环没有更多的行时,循环嵌套结束.另外,还 可以看出,这种连接方式需要内部循环的表有序(也就是有索引),并且外部循环表的行数要小于内部循环的行数,否则查询分析器就

SQL Server nested loop join 效率试验

从很多网页上都看到,SQL Server有三种Join的算法, nested loop join, merge join, hash join. 其中最常用的就是nested loop join. 在介绍nested loop join的很多文章里,都提到如果两个表做nested loop join,取行数较小的表作为外循环表,行数较多的表作为内循环表, join的效率会比较高. 其中之一的原因是如果内循环表做join的列上有合适的索引的话,那么外循环的每一条输入数据可以做索引的seek,这样就

禁用nested loop join里的spool

禁用nested loop join里的spool 转载自: https://blogs.msdn.microsoft.com/psssql/2015/12/15/spool-operator-and-trace-flag-8690/ https://answers.sqlperformance.com/questions/698/lazy-spool.html 在nested loop join里常常会看到一个spool操作符 这个spool 又名'performance spool',目的是

使用map端连接结合分布式缓存机制实现Join算法

前面我们介绍了MapReduce中的Join算法,我们提到了可以通过map端连接或reduce端连接实现join算法,在文章中,我们只给出了reduce端连接的例子,下面我们说说使用map端连接结合分布式缓存机制实现Join算法 1.介绍 我们使用频道类型数据集和机顶盒用户数据集,进行连接,统计出每天.每个频道.每分钟的收视人数 2.数据集 频道类型数据集就是channelType.csv文件,如下示例 机顶盒用户数据集来源于“08.统计电视机顶盒中无效用户数据,并以压缩格式输出有效数据”这个实

深入理解Oracle表(3):三大表连接方式详解之Nested loop join和 Sort merge join

深入理解Oracle表(3):三大表连接方式详解之Nested loop join和 Sort merge join 分类: Oracle 基础管理 Oracle SQL 开发2013-01-28 00:33 2536人阅读 评论(1) 收藏 举报 关系数据库技术的精髓就是通过关系表进行规范化的数据存储       并通过各种表连接技术和各种类型的索引技术来进行信息的检索和处理       这里Think愿意和大家一起来学习分享Oracle的三大表连接技术              在早期版本,

MySQL Join算法与调优白皮书(一)

正文 Inside君发现很少有人能够完成讲明白MySQL的Join类型与算法,网上流传着的要提升Join性能,加大变量join_buffer_size的谬论更是随处可见.当然,也有一些无知的PGer攻击MySQL不支持Hash Join,所以不适合一些分析类的操作.MySQL的确不支持Hash Join,也不支持Sort Merge Join,但是MySQL在Join上也有自己的独特的优化与处理,此外,分支版本MariaDB已支持Hash Join,因此拿MySQL来做一些"简单"的分

MySQL Join算法与调优白皮书(二)

Index Nested-Loop Join (接上篇)由于访问的是辅助索引,如果查询需要访问聚集索引上的列,那么必要需要进行回表取数据,看似每条记录只是多了一次回表操作,但这才是INLJ算法最大的弊端.首先,辅助索引的index lookup是比较随机I/O访问操作.其次,根据index lookup再进行回表又是一个随机的I/O操作.所以说,INLJ最大的弊端是其可能需要大量的离散操作,这在SSD出现之前是最大的瓶颈.而即使SSD的出现大幅提升了随机的访问性能,但是对比顺序I/O,其还是慢了

oracle多表连接方式Hash Join Nested Loop Join Merge Join

在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式:        嵌套循环(Nested  Loops (NL))      (散列)哈希连接(Hash Join (HJ))    (归并)排序合并连接(Sort Merge Join (SMJ) ) 二.连接说明:    1.Oracle一次只能连接两个表.不管查询中有多少个表,Oracle 在连接中一次仅能操作两张表.    2.当执行多个表的连接时,优化