Heim  >  Artikel  >  Datenbank  >  MySQL数据库下limit与join的优化方案

MySQL数据库下limit与join的优化方案

WBOY
WBOYOriginal
2016-06-07 16:14:041280Durchsuche

以下的文章主要描述的是MySQL数据库下limit与join的实际优化方案,我们大家都知道其在实际中的应用比例还是占为多数的,如果你对这一技术,心存好奇的话,以下的文章将会揭开它的神秘面纱。 PHP中分页肯定会使用到MySQL的limit,大部分对类似select * from ti

以下的文章主要描述的是MySQL数据库下limit与join的实际优化方案,我们大家都知道其在实际中的应用比例还是占为多数的,如果你对这一技术,心存好奇的话,以下的文章将会揭开它的神秘面纱。

PHP中分页肯定会使用到MySQL的limit,大部分对类似”select * from title where uid =** order by id desc limit m,n”很熟悉,也不是全部都能看出里面有什么不对,可是当是在大数据量下操作呢,比如百万类似”select * from title where uid =177 order by id desc limit 1234567,20″就会发现sql执行的时间明显变得很长,为什么呢?

先从MySQL数据库的limit原理说起,使用limit m,n是时候,MySQL先扫描(m+n)条记录,然后从m行开始取n行.比如上面的例子就是先扫描1234587条数据,这样的话sql能快吗?这就要 求我们尽可能的减少m的值,甚至没有m直接limit n这样是sql.

看个例子:

<ol class="dp-xml">
<li class="alt"><span><span>mysql</span><span class="tag">></span><span> select id,substr(mobile from 1 for 7),time,cpid,linkid from cp_mo100227 where </span><span class="attribute">cpid</span><span>=</span><span class="attribute-value">769</span><span> limit 888888,10;  </span></span></li>
<li><span>+———-+—————————–+———————+——+———————-+  </span></li>
<li class="alt"><span>| id | substr(mobile from 1 for 7) | time | cpid | linkid |  </span></li>
<li><span>+———-+—————————–+———————+——+———————-+  </span></li>
<li class="alt"><span>| 11535090 | 1353554 | 2010-02-24 21:07:48 | 769 | 21064905903309587933 |  </span></li>
<li><span>| 11535091 | 1353750 | 2010-02-24 21:07:48 | 769 | 21064912943389480033 |  </span></li>
<li class="alt"><span>| 11535093 | 1353394 | 2010-02-24 21:07:48 | 769 | 21064912945389480075 |  </span></li>
<li><span>| 11535098 | 1343073 | 2010-02-24 21:07:50 | 769 | 21064905865309587977 |  </span></li>
<li class="alt"><span>| 11535100 | 1369270 | 2010-02-24 21:07:51 | 769 | 21064926770369210194 |  </span></li>
<li><span>| 11535103 | 1355683 | 2010-02-24 21:07:51 | 769 | 21064912944389480113 |  </span></li>
<li class="alt"><span>| 11535104 | 1368959 | 2010-02-24 21:07:51 | 769 | 21064902508384448468 |  </span></li>
<li><span>| 11535105 | 1365243 | 2010-02-24 21:07:51 | 769 | 21064905907309403124 |  </span></li>
<li class="alt"><span>| 11535106 | 1362145 | 2010-02-24 21:07:52 | 769 | 21065002511384448497 |  </span></li>
<li><span>| 11535107 | 1369228 | 2010-02-24 21:07:52 | 769 | 21064902514384448437 |  </span></li>
<li class="alt"><span>+———-+—————————–+———————+——+———————-+  </span></li>
<li><span>10 rows in set (3.84 sec)  </span></li>
<li class="alt"><span> </span></li>
<li>
<span>mysql</span><span class="tag">></span><span> select id,substr(mobile from 1 for 7),time,cpid,linkid from cp_mo100227 where </span><span class="attribute">cpid</span><span>=</span><span class="attribute-value">769</span><span> and id</span><span class="tag">></span><span>=11535090 limit 10;  </span>
</li>
<li class="alt"><span>+———-+—————————–+———————+——+———————-+  </span></li>
<li><span>| id | substr(mobile from 1 for 7) | time | cpid | linkid |  </span></li>
<li class="alt"><span>+———-+—————————–+———————+——+———————-+  </span></li>
<li><span>| 11535090 | 1353554 | 2010-02-24 21:07:48 | 769 | 21064905903309587933 |  </span></li>
<li class="alt"><span>| 11535091 | 1353750 | 2010-02-24 21:07:48 | 769 | 21064912943389480033 |  </span></li>
<li><span>| 11535093 | 1353394 | 2010-02-24 21:07:48 | 769 | 21064912945389480075 |  </span></li>
<li class="alt"><span>| 11535098 | 1343073 | 2010-02-24 21:07:50 | 769 | 21064905865309587977 |  </span></li>
<li><span>| 11535100 | 1369270 | 2010-02-24 21:07:51 | 769 | 21064926770369210194 |  </span></li>
<li class="alt"><span>| 11535103 | 1355683 | 2010-02-24 21:07:51 | 769 | 21064912944389480113 |  </span></li>
<li><span>| 11535104 | 1368959 | 2010-02-24 21:07:51 | 769 | 21064902508384448468 |  </span></li>
<li class="alt"><span>| 11535105 | 1365243 | 2010-02-24 21:07:51 | 769 | 21064905907309403124 |  </span></li>
<li><span>| 11535106 | 1362145 | 2010-02-24 21:07:52 | 769 | 21065002511384448497 |  </span></li>
<li class="alt"><span>| 11535107 | 1369228 | 2010-02-24 21:07:52 | 769 | 21064902514384448437 |  </span></li>
<li><span>+———-+—————————–+———————+——+———————-+  </span></li>
<li class="alt"><span>10 rows in set (0.00 sec)  </span></li>
<li><span> </span></li>
<li class="alt">
<span>mysql</span><span class="tag">></span><span> select id,substr(mobile from 1 for 7),time,cpid,linkid from cp_mo100227 where </span><span class="attribute">cpid</span><span>=</span><span class="attribute-value">769</span><span> and time</span><span class="tag">></span><span>=’2010-02-24 21:07:48′ limit 10;  </span>
</li>
<li><span>+———-+—————————–+———————+——+———————-+  </span></li>
<li class="alt"><span>| id | substr(mobile from 1 for 7) | time | cpid | linkid |  </span></li>
<li><span>+———-+—————————–+———————+——+———————-+  </span></li>
<li class="alt"><span>| 11535090 | 1353554 | 2010-02-24 21:07:48 | 769 | 21064905903309587933 |  </span></li>
<li><span>| 11535091 | 1353750 | 2010-02-24 21:07:48 | 769 | 21064912943389480033 |  </span></li>
<li class="alt"><span>| 11535093 | 1353394 | 2010-02-24 21:07:48 | 769 | 21064912945389480075 |  </span></li>
<li><span>| 11535098 | 1343073 | 2010-02-24 21:07:50 | 769 | 21064905865309587977 |  </span></li>
<li class="alt"><span>| 11535100 | 1369270 | 2010-02-24 21:07:51 | 769 | 21064926770369210194 |  </span></li>
<li><span>| 11535103 | 1355683 | 2010-02-24 21:07:51 | 769 | 21064912944389480113 |  </span></li>
<li class="alt"><span>| 11535104 | 1368959 | 2010-02-24 21:07:51 | 769 | 21064902508384448468 |  </span></li>
<li><span>| 11535105 | 1365243 | 2010-02-24 21:07:51 | 769 | 21064905907309403124 |  </span></li>
<li class="alt"><span>| 11535106 | 1362145 | 2010-02-24 21:07:52 | 769 | 21065002511384448497 |  </span></li>
<li><span>| 11535107 | 1369228 | 2010-02-24 21:07:52 | 769 | 21064902514384448437 |  </span></li>
<li class="alt"><span>+———-+—————————–+———————+——+———————-+  </span></li>
<li><span>10 rows in set (0.01 sec) </span></li>
</ol>

例中数据表id是主键,time也建了索引,表中总数据约为240w行,其中cpid为769的数据量大约为90w条.这里面的id和时间可能会是不连续的.故不能直接得获取id>m这样操作

所以可以显示 “1,2,3,4,5,末页” 或是 “首页,>末页”这样,这样可以极大的减少m值!

MySQL里面的join顺便说一句就是,通常有点讲究的是用小表去驱动大表,而由于MySQL join实现的原理就是做循环比如left join就是对左边的数据进行循环去驱动右边的表,比如左边是可能会有m条记录匹配,右边有n条记录那么就是做m次循环,每次扫描n行数据,总扫面行数是 m*n行数据.左边返回的结果集的大小就决定了循环的次数,故单纯的用小表去驱动大表不一定的正确的。

小表的结果集可能也大于大表的结果集,所以写 join的时候尽可能的先估计两张表的可能结果集,用小结果集去驱动大结果集.值得注意的是在使用left/right join的时候,从表的条件应写在on之后,主表应写在where之后.否则MySQL数据库会当作普通的连表查询!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn