zoukankan      html  css  js  c++  java
  • MySQL具体解释(19)----------海量数据分页查询优化

    分页的详细解说解说请看http://blog.csdn.net/u011225629/article/details/46775947

    查看代码打印1 SELECT * FROM table ORDER BY id LIMIT 1000,10;
    以上SQL语句在原理上和在实际操作中是不会存在什么问题,可是当table表的数据量达到几十万以上的时候。上面的语句运行一遍,可能会要运行个十几秒的时间,而且当页数越靠后的话,运行的时间会越长。这个时候我们就须要找到一种更快的查询办法来替代这样的操作了。

    网上已经有非常多优化的方法。基本都是这种:

    查看代码打印1 SELECT * FROM table WHERE id >= (SELECT id FROM table LIMIT 1000000, 1) LIMIT 10;
    以上SQL语句是一个不错的解决方法。分页查询的速度基本会保持在1秒之内。但据经验总结得出另一种更好的办法,例如以下:

    查看代码打印1 SELECT * FROM table WHERE id BETWEEN 1000000 AND 1000010;
    相比以上的解决的方法,在速度上还会快了不少。

    另外分享两个关于查询的技巧:

    (1)假设须要查询 id 不是连续的一段,最佳的做法就是先找出 id ,然后用 in 查询:

    查看代码打印1 SELECT * FROM table WHERE id IN(10000, 100000, 1000000...);
    (2)当查询字段一较长字符串的时候,表设计时要为该字段多加一个字段,如存储网址的字段。在须要查询该字段的时候,不要直接查询字符串,效率低下。应该查诡该字串的crc32或md5值。

    怎样优化Mysql千万级高速分页。下面摘抄与网上,读者自行參考。

    MySql 性能究竟能有多高?用了php半年多,真正如此深入的去思考这个问题还是从前天開始。有过痛苦有过绝望。到如今充满信心!MySql 这个数据库绝对是适合dba级的高手去玩的,一般做一点1万篇新闻的小型系统怎么写都能够。用xx框架能够实现高速开发。

    但是数据量到了10万,百万至千万,他的性能还能那么高吗?一点小小的失误,可能造成整个系统的改写。甚至更本系统无法正常执行。好了。不那么多废话了。用事实说话,看样例:

    数据表 collect ( id, title ,info ,vtype) 就这4个字段,当中 title 用定长,info 用text, id 是逐渐。vtype是tinyint,vtype是索引。这是一个主要的新闻系统的简单模型。

    如今往里面填充数据,填充10万篇新闻。

    最后collect 为 10万条记录,数据库表占用硬盘1.6G。OK ,看以下这条sql语句:

    select id,title from collect limit 1000,10; 非常快;基本上0.01秒就OK,再看以下的

    select id,title from collect limit 90000,10; 从9万条開始分页。结果?

    8-9秒完毕。my god 哪出问题了?事实上要优化这条数据,网上找得到答案。

    看以下一条语句:

    select id from collect order by id limit 90000,10;

    非常快,0.04秒就OK。 为什么?由于用了id主键做索引当然快。

    网上的改法是:

    select id,title from collect where id>=(select id from collect order by id limit 90000,1) limit 10;

    这就是用了id做索引的结果。但是问题复杂那么一点点。就完了。看以下的语句

    select id from collect where vtype=1 order by id limit 90000,10; 非常慢。用了8-9秒!

    到了这里我相信非常多人会和我一样,有崩溃感觉!vtype 做了索引了啊?怎么会慢呢?vtype做了索引是不错,你直接

    select id from collect where vtype=1 limit 1000,10;

    是非常快的。基本上0.05秒,但是提高90倍,从9万開始。那就是0.05*90=4.5秒的速度了。和測试结果8-9秒到了一个数量级。从这里開始有人提出了分表的思路。这个和dis #cuz 论坛是一样的思路。思路例如以下:

    建一个索引表: t (id,title,vtype) 并设置成定长,然后做分页,分页出结果再到 collect 里面去找info 。 是否可行呢?实验下就知道了。

    10万条记录到 t(id,title,vtype) 里,数据表大小20M左右。用

    select id from t where vtype=1 order by id limit 90000,10;

    非常快了。基本上0.1-0.2秒能够跑完。

    为什么会这样呢?我猜想是由于collect 数据太多。所以分页要跑非常长的路。limit 全然和数据表的大小有关的。事实上这样做还是全表扫描,仅仅是由于数据量小,仅仅有10万才快。OK, 来个疯狂的实验,加到100万条,測试性能。加了10倍的数据,立即t表就到了200多M,并且是定长。还是刚才的查询语句。时间是0.1-0.2秒完毕!分表性能没问题?错!

    由于我们的limit还是9万。所以快。给个大的,90万開始

    select id from t where vtype=1 order by id limit 900000,10;

    看看结果。时间是1-2秒!

    why ?

    分表了时间还是这么长,非常之郁闷!有人说定长会提高limit的性能,開始我也以为。由于一条记录的长度是固定的,mysql 应该能够算出90万的位置才对啊?但是我们高估了mysql 的智能。他不是商务数据库,事实证明定长和非定长对limit影响不大?怪不得有人说discuz到了100万条记录就会非常慢。我相信这是真的,这个和数据库设计有关!

    难道MySQL 无法突破100万的限制吗???到了100万的分页就真的到了极限?

    答案是: NO 为什么突破不了100万是由于不会设计mysql造成的。

    以下介绍非分表法。来个疯狂的測试!

    一张表搞定100万记录,而且10G 数据库。怎样高速分页!
     
    好了,我们的測试又回到 collect表,開始測试结论是:

    30万数据,用分表法可行,超过30万他的速度会慢道你无法忍受!

    当然假设用分表+我这样的方法。那是绝对完美的。可是用了我这样的方法后,不用分表也能够完美解决!
     
    答 案就是:复合索引!

    有一次设计mysql索引的时候,无意中发现索引名字能够任取。能够选择几个字段进来,这有什么用呢?開始的

    select id from collect order by id limit 90000,10;

    这么快就是由于走了索引,但是假设加了where 就不走索引了。抱着试试看的想法加了 search(vtype,id) 这种索引。然后測试

    select id from collect where vtype=1 limit 90000,10; 很快!0.04秒完毕。

    再測试: select id ,title from collect where vtype=1 limit 90000,10; 很遗憾,8-9秒,没走search索引。

    再測试:search(id,vtype),还是select id 这个语句,也很遗憾。0.5秒。

    综上:假设对于有where 条件,又想走索引用limit的。必须设计一个索引,将where 放第一位,limit用到的主键放第2位,并且仅仅能select 主键!

    完美攻克了分页问题了。

    能够高速返回id就有希望优化limit , 按这种逻辑。百万级的limit 应该在0.0x秒就能够分完。

    看来mysql 语句的优化和索引时很重要的!
     
    好了。回到原题,怎样将上面的研究成功高速应用于开发呢?假设用复合查询,我的轻量级框架就没的用了。分页字符串还得自己写,那多麻烦?这里再看一个样例,思路就出来了:

    select * from collect where id in (9000,12,50,7000); 居然 0秒就能够查完!

    mygod ,mysql 的索引居然对于in语句相同有效!

    看来网上说in无法用索引是错误的!

    有了这个结论,就能够非常easy的应用于轻量级框架了:

     通过简单的变换,事实上思路非常easy:

    (1)通过优化索引。找出id。并拼成 “123,90000,12000″ 这种字符串。

    (2)第2次查询找出结果。小小的索引+一点点的修改就使mysql 能够支持百万甚至千万级的高效分页。

    通过这里的样例,我反思了一点:对于大型系统。PHP千万不能用框架,尤其是那种连sql语句都看不到的框架!

    由于開始对于我的轻量级框架都差点崩溃!仅仅适合小型应用的高速开发。对于ERP,OA,大型站点,数据层包含逻辑层的东西都不能用框架。假设程序猿失去了对sql语句的把控,那项目的风险将会成几何级数添加!

    尤其是用mysql 的时候。mysql 一定须要专业的dba 才干够发挥他的最佳性能。

    一个索引所造成的性能区别可能是上千倍。

  • 相关阅读:
    (Java) LeetCode 44. Wildcard Matching —— 通配符匹配
    (Java) LeetCode 30. Substring with Concatenation of All Words —— 与所有单词相关联的字串
    (Java) LeetCode 515. Find Largest Value in Each Tree Row —— 在每个树行中找最大值
    (Java) LeetCode 433. Minimum Genetic Mutation —— 最小基因变化
    (Java) LeetCode 413. Arithmetic Slices —— 等差数列划分
    (Java) LeetCode 289. Game of Life —— 生命游戏
    (Java) LeetCode 337. House Robber III —— 打家劫舍 III
    (Java) LeetCode 213. House Robber II —— 打家劫舍 II
    (Java) LeetCode 198. House Robber —— 打家劫舍
    (Java) LeetCode 152. Maximum Product Subarray —— 乘积最大子序列
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5202846.html
Copyright © 2011-2022 走看看