发布于 2014-08-19 05:46:13 | 504 次阅读 | 评论: 0 | 来源: 网友投递

这里有新鲜出炉的Mysql教程,程序狗速度看过来!

Mysql关系型数据库管理系统

MySQL是一个开放源码的小型关联式数据库管理系统,开发者为瑞典MySQL AB公司。MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。


本文讲解的是mysql的分页limit优化,mysql的分页比较简单,只需要limit offset,length就可以获取数据了,但是当offset和length比较大的时候,mysql明显性能下降

1.子查询优化法
先找出第一条数据,然后大于等于这条数据的id就是要获取的数据
缺点:数据必须是连续的,可以说不能有where条件,where条件会筛选数据,导致数据失去连续性

实验下

    mysql> set profiling=1;  
    Query OK, 0 rows affected (0.00 sec)  
      
    mysql> select count(*) from Member;  
    +----------+  
    | count(*) |  
    +----------+  
    |   169566 |   
    +----------+  
    1 row in set (0.00 sec)  
      
    mysql> pager grep !~-  
    PAGER set to 'grep !~-'  
      
    mysql> select * from Member limit 10, 100;  
    100 rows in set (0.00 sec)  
      
    mysql> select * from Member where MemberID >= (select MemberID from Member limit 10,1) limit 100;  
    100 rows in set (0.00 sec)  
      
    mysql> select * from Member limit 1000, 100;  
    100 rows in set (0.01 sec)  
      
    mysql> select * from Member where MemberID >= (select MemberID from Member limit 1000,1) limit 100;  
    100 rows in set (0.00 sec)  
      
    mysql> select * from Member limit 100000, 100;  
    100 rows in set (0.10 sec)  
      
    mysql> select * from Member where MemberID >= (select MemberID from Member limit 100000,1) limit 100;  
    100 rows in set (0.02 sec)  
      
    mysql> nopager  
    PAGER set to stdout  
      
      
    mysql> show profiles\G  
    *************************** 1. row ***************************  
    Query_ID: 1  
    Duration: 0.00003300  
       Query: select count(*) from Member  
      
    *************************** 2. row ***************************  
    Query_ID: 2  
    Duration: 0.00167000  
       Query: select * from Member limit 10, 100  
    *************************** 3. row ***************************  
    Query_ID: 3  
    Duration: 0.00112400  
       Query: select * from Member where MemberID >= (select MemberID from Member limit 10,1) limit 100  
      
    *************************** 4. row ***************************  
    Query_ID: 4  
    Duration: 0.00263200  
       Query: select * from Member limit 1000, 100  
    *************************** 5. row ***************************  
    Query_ID: 5  
    Duration: 0.00134000  
       Query: select * from Member where MemberID >= (select MemberID from Member limit 1000,1) limit 100  
      
    *************************** 6. row ***************************  
    Query_ID: 6  
    Duration: 0.09956700  
       Query: select * from Member limit 100000, 100  
    *************************** 7. row ***************************  
    Query_ID: 7  
    Duration: 0.02447700  
       Query: select * from Member where MemberID >= (select MemberID from Member limit 100000,1) limit 100  

 

从结果中可以得知,当偏移1000以上使用子查询法可以有效的提高性能。


2.倒排表优化法
倒排表法类似建立索引,用一张表来维护页数,然后通过高效的连接得到数据

缺点:只适合数据数固定的情况,数据不能删除,维护页表困难


3.反向查找优化法
当偏移超过一半记录数的时候,先用排序,这样偏移就反转了

缺点:order by优化比较麻烦,要增加索引,索引影响数据的修改效率,并且要知道总记录数
,偏移大于数据的一半

引用
limit偏移算法:
正向查找: (当前页 - 1) * 页长度
反向查找: 总记录 - 当前页 * 页长度


做下实验,看看性能如何

总记录数:1,628,775
每页记录数: 40
总页数:1,628,775 / 40 = 40720
中间页数:40720 / 2 = 20360

第21000页
正向查找SQL:

    SELECT * FROM `abc` WHERE `BatchID` = 123 LIMIT 839960, 40  


时间:1.8696 秒

反向查找sql:

    SELECT * FROM `abc` WHERE `BatchID` = 123 ORDER BY InputDate DESC LIMIT 788775, 40  


时间:1.8336 秒

第30000页
正向查找SQL:

    SELECT * FROM `abc` WHERE `BatchID` = 123 LIMIT 1199960, 40  


时间:2.6493 秒

反向查找sql:

    SELECT * FROM `abc` WHERE `BatchID` = 123 ORDER BY InputDate DESC LIMIT 428775, 40  


时间:1.0035 秒

注意,反向查找的结果是是降序desc的,并且InputDate是记录的插入时间,也可以用主键联合索引,但是不方便。


4.limit限制优化法
把limit偏移量限制低于某个数。。超过这个数等于没数据,我记得alibaba的dba说过他们是这样做的

5.只查索引法

    1.uuid用binary保存
    建议uuid不要使用char来保存,而用binary(16)来保存。这里在长度上来讲用binary会节省一半。因为一个字符占用1个字节,而一个字节实际上可以表示0-256(2^8),用16进制的表示需要2个字节00-FF(0-256)。
    优化前:SET uuid = UUID() (类型:char(36))
    优化后:SET uuid = HEX(REPLACE(UUID(), '-', '')) (类型:binary(16))

    2.用crc32替换长字符串的查找
    如果索引列是个很长的字符串,例如url。那可以再建立一个列用来保存这个列的crc32结果,以提高索引的使用速度。
    优化前:WHERE url = 'http://www.domain.com/' (索引:url,类型:var/char(?))
    优化后:WHERE url_crc32 = CRC32('http://www.domain.com/') AND url = 'http://www.domain.com/' (索引:url_crc32,类型:unsigned int)

    3.前缀索引和后缀索引
    前缀索引听得比较多,优点是减少索引的长度,缺点是排序不能使用前缀索引(影响distinct/order/group),也不会出现Covering Index(只读取索引就能满足查询)。
    后缀索引还是首次听到,孤陋寡闻了。因为MySQL不支持反向索引,所有有时候查询会有问题,例如字段blog保存用户的博客地址(http://www.domain.com),那需要查询某个域名有多少个用户就不好查询,可以用一个额外的字段反转保存。blog_reverse:moc.eyeavaj.willko://ptth,这样就很容易查到iteye.com(moc.eyeavaj)有多少用户了,并可以使用索引,也就是解决了 LIKE '%?'的问题,因为查询反转成LIKE '?%'了。

    4.散列数据
    散列数据就是把原本只有一条记录的散列成多条,充分利用InnoDB行锁的特性,提高并发。
    例如,之前是UPDATE hit_counter SET cnt = cnt + 1 WHERE id = ?
    散列后是 UPDATE hit_counter SET cnt = cnt + 1 WHERE id = ? AND slot = rand() * 100
    散列后查询需要合并数据。

    5.优化limit和offset
    MySQL的limit工作原理就是先读取n条记录,然后抛弃前n条,读m条想要的,所以n越大,性能会越差。
    优化前SQL: SELECT * FROM member ORDER BY last_active LIMIT 50,5
    优化后SQL: SELECT * FROM member INNER JOIN (SELECT member_id FROM member ORDER BY last_active LIMIT 50, 5) USING (member_id)
    分别在于,优化前的SQL需要更多I/O浪费,因为先读索引,再读数据,然后抛弃无需的行。而优化后的SQL(子查询那条)只读索引(Cover index)就可以了,然后通过member_id读取需要的列。


总结:limit的优化限制都比较多,所以实际情况用或者不用只能具体情况具体分析了。页数那么后,基本很少人看的。。。



最新网友评论  共有(0)条评论 发布评论 返回顶部

Copyright © 2007-2017 PHPERZ.COM All Rights Reserved   冀ICP备14009818号  版权声明  广告服务