mysql大数据量的大表分页优化,按照时间字段排序,该字段有重复值,同时与主键id排序不一致.

当表达到几十万条时, 使用limit语句分页查询将会出现问题.查询比较靠前的数据还好,但要是比较靠后的数据就会出现变得非常慢. 

需求: 有一个上百万行的大表, 需要按照其时间字段顺序分页读取, 该字段的顺序与主键id顺序并不一致. 而且该字段会有重复. 对于大表的分页网上方法是按照主键id顺序分页, 所以可以利用到主键id的递增特性达到效果: 如下面演示:

select * from table_name order by id asc limit 500000,10; //普通分页语句

//转换后的, 该语句查询非常快
select * from table_name where id > (select id from table_name order by id asc limit 500000,10) limit 10

   但是本需求中, 显然无法利用这个特性, 因其有重复值. 

 

解决方案: 

  1. 首先肯定是先对时间字段(假设该字段名为create_time)加上索引了, 加上索引后limit 0,10这种查询靠前的语句就非常快, 但是limit 500000,10语句这种查询靠后数据的查询就慢得令人发指, 一般需要好几秒. explain查询计划可以看到limit 50000.10这个语句mysql要先扫描前500000行后才能读到数据,所以这就非常慢了.
  2. 在步骤1上继续优化. 
    //对于几十万表基本都能在1s内查出来
    select * from table_name where id in (SELECT id from (select id from table_name LIMIT 500000,10) as tmp)  
    
    // 1.其中使用(SELECT id from (select id from table_name LIMIT 500000,10) as tmp)
         这种繁琐的写法是为了适应mysql5.6不支持子查询语句中有limit操作.当然你也可以将上述语句拆分成
         两条,先执行子查询获取id结果集, 然后在用id in id结果集语句获取最终结果也可.
    // 2.该句子主要时间花费在(SELECT id from (select id from table_name LIMIT 500000,10) as tmp) 
         子查询上, 而 id in的查询是非常快的,自己测试只要零点零几秒. 
    
    // 3.最后要强调的是以上例子写法比较简化,查询只取出自己需要的列,不要列就不要取出,因为取出不需要的列
         时,传送数据的时间会加大以及其他的一些开销,尤其是无用的列很多很大时. 所以select *写法要根据你
         的业务需要调整,有时候这个方面的耗时还是很大的,一定引起重视.

   锦上添花的解决方案(利用mysql本身的查询缓存, 可只针对某些语句缓存)

    使用条件: (首先要是已经正在使用mysql查询缓存,那么这部分就可不看了)如果你要优化的这个查询语句基本上是不变的, 例如你应用的一些公共数据(如首页), 那么这些只需要查询一遍缓存起来,后续相同的查询就可以直接使用,这样速度是非常快的. 正好mysql是提供了查询缓存这个功能, 什么?你只要缓存一些特定的语句, 不想因优化一条语句而整个应用的所有语句都用上查询缓存, 要知道查询也是有开销的, 对于一些语句是没有帮助甚至会使其变慢. 凑巧, mqsql也支持只对指定的语句进行缓存其他语句不受影响.

    mysql的查询缓存初步了解:  

 mysql的查询缓存功能由query_cache_type系统变量控制,有如下取值:
   OFF:表示不开启查询
   ON: 表示对所有语句都开启查询缓存, 除非sql语句以SELECT SQL_NO_CACHE开头明确表示不对该句子缓存
   DEMAND: 当语句以select SQL_CACHE开头的才会缓存

     代码实现

1.找到你的mysql配置文件在 [mysqld] 块下添加以下内容
  [mysqld]
  query_cache_type=2
  
2. 然后重启你的mysql服务, 进入mysql命令行,执行如下命令
   show variables like "query_cache_type"; //再次确认下查询缓存是否开启
   show variables like "query_cache_size"; //确认查询缓存大小,注意需要大于0
   set global query_cache_size = 1048576 //设置查询缓存大小,可设置的值为1024倍数(单位byte)需要大于40k
3. 对于你要缓存的select语句使用 SELECT SQL_CACHE开头, 以下举个栗子:
   SELECT SQL_CACHE * from table_name order by create_time desc limit 50000, 10;
   当mysql看到SELECT SQL_CACHE开头时会去查询缓存中找有没有缓存过,没有则执行语句并将结果缓存起来以供后续相同的查询使用.

猜你喜欢

转载自blog.csdn.net/weixin_37281289/article/details/103681635