了解MySQL联表查询中的驱动表,优化查询,以小表驱动大表

余生长醉 提交于 2021-02-13 11:59:01

<div class="htmledit_views">

<p><span style="font-size:24px;">一、为什么要用小表驱动大表</span></p> <p><span style="font-size:14px;">1、驱动表的定义<br></span></p> <p><span style="font-size:24px;"></span></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> <span style="font-size:14px;">当进行多表连接查询时, [驱动表] 的定义为:</span></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> <span style="font-size:14px;">1)指定了联接条件时,满足查询条件的记录行数少的表为[驱动表]</span></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> <span style="font-size:14px;">2)未指定联接条件时,行数少的表为[驱动表](Important!)</span></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> <span style="font-size:14px;">忠告:如果你搞不清楚该让谁做驱动表、谁 join 谁,请让 MySQL 运行时自行判断</span></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> <span style="font-size:14px;">既然“未指定联接条件时,行数少的表为[驱动表]”了,而且你也对自己写出的复杂的 Nested Loop Join 不太有把握(如下面的实例所示),就别指定谁 left/right join 谁了,请交给 MySQL优化器 运行时决定吧。</span></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> <span style="font-size:14px;"><span style="line-height:1.5;">如果您对自己特别有信心</span></span></p> <br><p><span style="font-size:24px;"><span style="font-size:14px;">2、mysql关联查询的概念:</span><br></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;">MySQL 表关联的算法是 Nest Loop Join,是通过驱动表的结果集作为循环基础数据,然后一条一条地通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。</span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;"><br></span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;">例: user表10000条数据,class表20条数据<br></span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;">select * from user u left join class c u.userid=c.userid</span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;">这样则需要用user表循环10000次才能查询出来,而如果用class表驱动user表则只需要循环20次就能查询出来</span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;">例:</span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;">select * from class c left join user u c.userid=u.userid</span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;"><br></span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;"></span></span></p> <h2 id="articleHeader3" style="margin:0px 0px 10px;padding:3px 10px;border-width:0px 0px 0px 10px;border-left-style:solid;border-left-color:rgb(111,168,51);font-size:15px;font-weight:normal;font-family:Arial, Helvetica, sans-serif;line-height:22.5px;color:rgb(111,168,51);"> <span style="line-height:1.5;">小结果集驱动大结果集</span></h2> <p></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> <span style="line-height:1.5;">de.cel 在2012年总结说,不管是你,还是 MySQL,</span><span style="line-height:1.5;"></span><span style="line-height:1.5;">优化的目标是尽可能减少JOIN中Nested Loop的循环次数。</span></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> <span style="line-height:1.5;">以此保证:永远用小结果集驱动大结果集(Important)!</span></p> <span style="font-size:24px;"><br> 二、优化联表查询</span><br><p><span style="font-size:24px;"><span style="font-size:14px;">优化第一步之:根据驱动表的字段排序</span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;"><br> left join不变,干嘛要根据非驱动表的字段排序呢?我们前面说过“对驱动表可以直接排序,对非驱动表(的字段排序)需要对循环查询的合并结果(临时表)进行排序!”的。<br><br> explain<br><br> SELECT mb.id…… <br><br> FROM mb LEFT JOIN mbei ON mb.id=mbei.mb_id INNER JOINu ON mb.uid=u.uid &nbsp;<br><br> WHERE 1=1 &nbsp;<br><br> ORDER BY mb.id DESC<br><br> limit 0,10<br><br> 也满足业务场景,做到了rows最小:</span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;"><br></span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;"></span></span></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> 优化第二步:去除所有JOIN,让MySQL自行决定,explain第一张表就是驱动表,数据量比其它两张表都要小!</p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> <span style="line-height:1.5;"></span></p> <pre class="prettyprint lang-bsh hljs sql" style="margin-top:10px;margin-bottom:10px;padding:.5em;border:1px solid rgb(204,204,204);white-space:pre-wrap;overflow:auto;color:rgb(101,123,131);background:rgb(253,246,227);" name="code"><span class="hljs-operator"><span class="hljs-keyword">explain</span></br> <span class="hljs-keyword">SELECT</span> mb.id…… </br> <span class="hljs-keyword">FROM</span> mb,mbei,u </br> <span class="hljs-keyword">WHERE</span> </br> mb.id=mbei.mb_id</br> <span class="hljs-keyword">and</span> mb.uid=u.user_id</br> <span class="hljs-keyword">order</span> <span class="hljs-keyword">by</span> mbei.apply_time <span class="hljs-keyword">desc</span></br> <span class="hljs-keyword">limit</span> <span class="hljs-number" style="color:#2aa198;">0</span>,<span class="hljs-number" style="color:#2aa198;">10</span></span></pre> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> 立竿见影,驱动表一样是小表 mbei:</p> <pre class="prettyprint lang-html hljs xml" style="margin-top:10px;margin-bottom:10px;padding:.5em;border:1px solid rgb(204,204,204);white-space:pre-wrap;overflow:auto;color:rgb(101,123,131);background:rgb(253,246,227);" name="code"><span class="widget-clipboard"></span>id select_type table type possible_keys key key_len ref rows Extra</br> 1 SIMPLE <span style="color:#CC0000;"><strong><span style="font-size:24px;"><span style="font-size:14px;">mbei</span></span> </strong></span>ALL mb_id (NULL) (NULL) (NULL) 13388 Using filesort</br> 1 SIMPLE mb eq_ref PRIMARY,userid PRIMARY 4 mbei.mb_id 1</br> 1 SIMPLE u eq_ref PRIMARY PRIMARY 4 mb.uid 1 Using index</pre><span style="font-size:24px;"><br></span></br> <p><span style="font-size:24px;"><span style="font-size:14px;"><span style="font-size:24px;">三、总结</span></span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;"></span></span></p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> 1、不要过于相信你的运气!</p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> 2、不要相信你的开发环境里SQL的执行速度!</p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> 3、请拿起 explain 武器,如果你看到以下现象,请优化:</p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> 1)出现了Using temporary</p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> 2)rows过多,或者几乎是全表的记录数</p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> 3)key 是 (NULL)</p> <p style="margin-top:0px;margin-bottom:0px;padding-top:0px;padding-bottom:0px;border:0px;"> 4)possible_keys 出现过多(待选)索引</p> <br><p><span style="font-size:24px;"><span style="font-size:14px;"></span></span></p> <blockquote> <div> <div><br></div> <br></div> </blockquote> <p></p> <p><span style="font-size:24px;"><span style="font-size:14px;"><br></span></span></p> <p><span style="font-size:24px;"><span style="font-size:14px;"><br></span></span></p> </div>

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!