当前位置: 首页 > news >正文

河北远策网站建设苏州 规划建设局网站

河北远策网站建设,苏州 规划建设局网站,WordPress手机菜单样式修改,环球贸易网官网Join语句执行流程 Hi#xff0c;我是阿昌#xff0c;今天学习记录的是关于Join语句执行流程的内容。 在实际生产中#xff0c;关于 join 语句使用的问题#xff0c;一般会集中在以下两类#xff1a; 不让使用 join#xff0c;使用 join 有什么问题呢#xff1f;如果有…Join语句执行流程 Hi我是阿昌今天学习记录的是关于Join语句执行流程的内容。 在实际生产中关于 join 语句使用的问题一般会集中在以下两类 不让使用 join使用 join 有什么问题呢如果有两个大小不同的表做 join应该用哪个表做驱动表呢 创建两个表 t1 和 t2 来说明。 CREATE TABLE t2 (id int(11) NOT NULL,a int(11) DEFAULT NULL,b int(11) DEFAULT NULL,PRIMARY KEY (id),KEY a (a) ) ENGINEInnoDB;drop procedure idata; delimiter ;; create procedure idata() begindeclare i int;set i1;while(i1000)doinsert into t2 values(i, i, i);set ii1;end while; end;; delimiter ; call idata();create table t1 like t2; insert into t1 (select * from t2 where id100)可以看到这两个表都有一个主键索引 id 和一个索引 a字段 b 上无索引。 存储过程 idata() 往表 t2 里插入了 1000 行数据在表 t1 里插入的是 100 行数据。 一、Index Nested-Loop Join 如果直接使用 join 语句MySQL 优化器可能会选择表 t1 或 t2 作为驱动表这样会影响分析 SQL 语句的执行过程。 所以为了便于分析执行过程中的性能问题改用 straight_join 让 MySQL 使用固定的连接方式执行查询这样优化器只会按照指定的方式去 join。 来看一下这个语句 select * from t1 straight_join t2 on (t1.at2.a);在这个语句里t1 是驱动表t2 是被驱动表。 现在来看一下这条语句的 explain 结果。 可以看到在这条语句里被驱动表 t2 的字段 a 上有索引join 过程用上了这个索引因此这个语句的执行流程是这样的 从表 t1 中读入一行数据 R从数据行 R 中取出 a 字段到表 t2 里去查找取出表 t2 中满足条件的行跟 R 组成一行作为结果集的一部分重复执行步骤 1 到 3直到表 t1 的末尾循环结束。 这个过程是先遍历表 t1然后根据从表 t1 中取出的每行数据中的 a 值去表 t2 中查找满足条件的记录。 在形式上这个过程就跟写程序时的嵌套查询类似并且可以用上被驱动表的索引所以称之为“Index Nested-Loop Join”简称 NLJ。它对应的流程图如下所示 在这个流程里 对驱动表 t1 做了全表扫描这个过程需要扫描 100 行而对于每一行 R根据 a 字段去表 t2 查找走的是树搜索过程。由于构造的数据都是一一对应的因此每次的搜索过程都只扫描一行也是总共扫描 100 行所以整个执行流程总扫描行数是 200。 能不能使用 join? 假设不使用 join那就只能用单表查询。 看看上面这条语句的需求用单表查询怎么实现。 执行select * from t1查出表 t1 的所有数据这里有 100 行循环遍历这 100 行数据 从每一行 R 取出字段 a 的值 $R.a执行select * from t2 where a$R.a把返回的结果和 R 构成结果集的一行。 可以看到在这个查询过程也是扫描了 200 行但是总共执行了 101 条语句比直接 join 多了 100 次交互。 除此之外客户端还要自己拼接 SQL 语句和结果。 显然这么做还不如直接 join 好。 怎么选择驱动表 在这个 join 语句执行过程中驱动表是走全表扫描而被驱动表是走树搜索。假设被驱动表的行数是 M。 每次在被驱动表查一行数据要先搜索索引 a再搜索主键索引。 每次搜索一棵树近似复杂度是以 2 为底的 M 的对数记为 log2M所以在被驱动表上查一行的时间复杂度是 2*log2M。 假设驱动表的行数是 N执行过程就要扫描驱动表 N 行然后对于每一行到被驱动表上匹配一次。 因此整个执行过程近似复杂度是 N N*2*log2M。 显然N 对扫描行数的影响更大因此应该让小表来做驱动表。 如果没觉得这个影响有那么“显然” 可以这么理解 N 扩大 1000 倍的话扫描行数就会扩大 1000 倍 而 M 扩大 1000 倍扫描行数扩大不到 10 倍。 小结一下通过上面的分析得到了两个结论 使用 join 语句性能比强行拆成多个单表执行 SQL 语句的性能要好如果使用 join 语句的话需要让小表做驱动表。 但是需要注意这个结论的前提是“可以使用被驱动表的索引”。 二、Simple Nested-Loop Join 再看看被驱动表用不上索引的情况。 现在把 SQL 语句改成这样 select * from t1 straight_join t2 on (t1.at2.b);由于表 t2 的字段 b 上没有索引因此再用图 2 的执行流程时每次到 t2 去匹配的时候就要做一次全表扫描。 你可以先设想一下这个问题继续使用图 2 的算法是不是可以得到正确的结果呢 如果只看结果的话这个算法是正确的而且这个算法也有一个名字叫做“Simple Nested-Loop Join”。 但是这样算来这个 SQL 请求就要扫描表 t2 多达 100 次总共扫描 100*100010 万行。 这还只是两个小表如果 t1 和 t2 都是 10 万行的表当然了这也还是属于小表的范围就要扫描 100 亿行这个算法看上去太“笨重”了。 三、Block Nested-Loop Join 当然MySQL 也没有使用这个 Simple Nested-Loop Join 算法而是使用了另一个叫作“Block Nested-Loop Join”的算法简称 BNL。 这时候被驱动表上没有可用的索引算法的流程是这样的 把表 t1 的数据读入线程内存 join_buffer 中由于我们这个语句中写的是 select *因此是把整个表 t1 放入了内存扫描表 t2把表 t2 中的每一行取出来跟 join_buffer 中的数据做对比满足 join 条件的作为结果集的一部分返回。 这个过程的流程图如下 对应地这条 SQL 语句的 explain 结果如下所示 可以看到在这个过程中对表 t1 和 t2 都做了一次全表扫描因此总的扫描行数是 1100。 由于 join_buffer 是以无序数组的方式组织的因此对表 t2 中的每一行都要做 100 次判断总共需要在内存中做的判断次数是100*100010 万次。 前面我们说过如果使用 Simple Nested-Loop Join 算法进行查询扫描行数也是 10 万行。因此从时间复杂度上来说这两个算法是一样的。但是Block Nested-Loop Join 算法的这 10 万次判断是内存操作速度上会快很多性能也更好。 在这种情况下应该选择哪个表做驱动表。 假设小表的行数是 N大表的行数是 M那么在这个算法里 两个表都做一次全表扫描所以总的扫描行数是 MN内存中的判断次数是 M*N。 可以看到调换这两个算式中的 M 和 N 没差别因此这时候选择大表还是小表做驱动表执行耗时是一样的。 这个例子里表 t1 才 100 行要是表 t1 是一个大表join_buffer 放不下怎么办呢 join_buffer 的大小是由参数 join_buffer_size 设定的默认值是 256k。如果放不下表 t1 的所有数据话策略很简单就是分段放。 join_buffer_size 改成 1200再执行 select * from t1 straight_join t2 on (t1.at2.b);执行过程就变成了 扫描表 t1顺序读取数据行放入 join_buffer 中放完第 88 行 join_buffer 满了继续第 2 步扫描表 t2把 t2 中的每一行取出来跟 join_buffer 中的数据做对比满足 join 条件的作为结果集的一部分返回清空 join_buffer继续扫描表 t1顺序读取最后的 12 行数据放入 join_buffer 中继续执行第 2 步。 执行流程图也就变成这样 图中的步骤 4 和 5表示清空 join_buffer 再复用。 这个流程才体现出了这个算法名字中“Block”的由来表示“分块去 join”。 可以看到这时候由于表 t1 被分成了两次放入 join_buffer 中导致表 t2 会被扫描两次。 虽然分成两次放入 join_buffer但是判断等值条件的次数还是不变的依然是 (8812)*100010 万次。 在这种情况下驱动表的选择问题。 假设驱动表的数据行数是 N需要分 K 段才能完成算法流程被驱动表的数据行数是 M。 注意这里的 K 不是常数N 越大 K 就会越大因此把 K 表示为λ*N显然λ的取值范围是 (0,1)。 所以在这个算法的执行过程中 扫描行数是 NλNM内存判断 N*M 次。 显然内存判断次数是不受选择哪个表作为驱动表影响的。 而考虑到扫描行数在 M 和 N 大小确定的情况下N 小一些整个算式的结果会更小。所以结论是应该让小表当驱动表。 在 NλNM 这个式子里λ才是影响扫描行数的关键因素这个值越小越好。 刚刚我们说了 N 越大分段数 K 越大。那么N 固定的时候什么参数会影响 K 的大小呢也就是λ的大小答案是 join_buffer_size。 join_buffer_size 越大一次可以放入的行越多分成的段数也就越少对被驱动表的全表扫描次数就越少。 如果你的 join 语句很慢就把 join_buffer_size 改大。 第一个问题能不能使用 join 语句 如果可以使用 Index Nested-Loop Join 算法也就是说可以用上被驱动表上的索引其实是没问题的如果使用 Block Nested-Loop Join 算法扫描行数就会过多。尤其是在大表上的 join 操作这样可能要扫描被驱动表很多次会占用大量的系统资源。所以这种 join 尽量不要用。 所以在判断要不要使用 join 语句时就是看 explain 结果里面Extra 字段里面有没有出现“Block Nested Loop”字样。 第二个问题是如果要使用 join应该选择大表做驱动表还是选择小表做驱动表 如果是 Index Nested-Loop Join 算法应该选择小表做驱动表如果是 Block Nested-Loop Join 算法 在 join_buffer_size 足够大的时候是一样的在 join_buffer_size 不够大的时候这种情况更常见应该选择小表做驱动表。 所以这个问题的结论就是总是应该使用小表做驱动表。 当然了这里我需要说明下什么叫作“小表”。 如果我在语句的 where 条件加上 t2.id50 这个限定条件再来看下这两条语句 select * from t1 straight_join t2 on (t1.bt2.b) where t2.id50; select * from t2 straight_join t1 on (t1.bt2.b) where t2.id50;注意为了让两条语句的被驱动表都用不上索引所以 join 字段都使用了没有索引的字段 b。 但如果是用第二个语句的话join_buffer 只需要放入 t2 的前 50 行显然是更好的。 所以这里“t2 的前 50 行”是那个相对小的表也就是“小表”。 再来看另外一组例子 select t1.b,t2.* from t1 straight_join t2 on (t1.bt2.b) where t2.id100; select t1.b,t2.* from t2 straight_join t1 on (t1.bt2.b) where t2.id100;这个例子里表 t1 和 t2 都是只有 100 行参加 join。 但是这两条语句每次查询放入 join_buffer 中的数据是不一样的 表 t1 只查字段 b因此如果把 t1 放到 join_buffer 中则 join_buffer 中只需要放入 b 的值表 t2 需要查所有的字段因此如果把表 t2 放到 join_buffer 中的话就需要放入三个字段 id、a 和 b。 应该选择表 t1 作为驱动表。也就是说在这个例子里“只需要一列参与 join 的表 t1”是那个相对小的表。 所以更准确地说在决定哪个表做驱动表的时候应该是两个表按照各自的条件过滤过滤完成之后计算参与 join 的各个字段的总数据量数据量小的那个表就是“小表”应该作为驱动表。 四、总结 如果可以使用被驱动表的索引join 语句还是有其优势的不能使用被驱动表的索引只能使用 Block Nested-Loop Join 算法这样的语句就尽量不要使用在使用 join 的时候应该让小表做驱动表。 使用 Block Nested-Loop Join 算法可能会因为 join_buffer 不够大需要对被驱动表做多次全表扫描。如果被驱动表是一个大表并且是一个冷数据表除了查询过程中可能会导致 IO 压力大以外觉得对这个 MySQL 服务还有什么更严重的影响吗 如果被驱动表是一个大表(因为不论用BNL还是ILJ算法) 都是优先让被参与join的总的字段量较大的一张表作为一个被驱动表。 但是由于关联的时候被驱动表的数据会频繁被走索引数 所以根据MYSQL 的LRU算法 其实冷数据也会被提到链表的前部 ,造成冷数据的前移其余业务数据被淘汰。 造成内存命中率降低。 请求响应变慢,业务可能造成阻塞。
http://www.w-s-a.com/news/263604/

相关文章:

  • 怎样做28网站代理中山网站建设方案外包
  • vs2010做网站前台搭建小网站
  • 做视频必须知道的一些网站wordpress 标签鼠标滑过_弹出的title 代码美化
  • 怎么做室内设计公司网站电商运营培训视频课程
  • 昆明网站策划天津市建筑信息平台
  • 三亚放心游app官方网站wordpress 个人主题
  • 做简单的网站备案平台新增网站
  • 中国建设网站银行网络营销推广方案整合
  • 网站域名列表dede网站白屏
  • 站长工具一区品牌建设卓有成效
  • 电子商务网站建设案例wordpress批量编辑
  • 想代理个网站建设平台100个最佳市场营销案例
  • 钟表东莞网站建设石家庄做网站时光
  • 织梦 图片网站源码成都建设工程安监局网站
  • 做兼职的网站策划书湖北省建设工程造价信息网
  • 企业网站网址长期做网站应该购买稳定的空间
  • 网站静态化设计html5手机网站制作
  • 深圳最简单的网站建设家居网站建设全网营销
  • 如何取消网站备案佛山网站优化公司
  • 网站开发 成都广水网站设计
  • 音乐网站建设目标合同管理系统
  • jq网站特效插件如何知道网站是否被k
  • 自己的网站怎么接广告网站搭建收费
  • 宁波大型网站制作建立一个网站 优帮云
  • 大连零基础网站建设教学电话有哪些比较好的做ppt好的网站
  • 哪个网站做logo设计我的建筑网
  • php电子商务网站开发沂源手机网站建设公司
  • html和php做网站哪个好3gcms企业手机网站整站源码asp
  • 网站建设网页设计案例云南建设厅网站删除
  • 杏坛网站制作太原做网站要多少钱呢