mysql查询导致内存过大问题

在查询数据库的时候,由于数据量大,我要做分页,然后首先获取总的条数,但是使用sql语句SELECT COUNT(*) as total from WHERE addtime between 1164038401 and 1511235339;这条sql等于遍历了全表,数据有一百万条,id为主键索引,addtime为普通索引。现在问题是一使用这条语句内存使用量就从一开始的30%多直接上升到90%多,怎么解决这个内存问题?
我现在只是查询个数,但是分页的时候会查询有条件的大量数据,对于内存过大,有什么好的解决办法?比如sql不使用缓存,修改配置文件等等。
求大神指导,谢谢!

阅读 5.8k
8 个回答

对于几百万行+的大表来说,COUNT(*)是非常耗时的,你看能不能换个方式处理下。

要么在业务上索性就不统计,你想想你做分页,每页10条数据,两百万行就是 20 万页,你统计了别人会翻这么多页吗。

另一种方式就是如果你的主键是连续递增的,就可以通过边界值相减得到统计结果,这比你直接 count 肯定是减少了不少时间。

MyISAM引擎中count(*)非常快, 可以用下面这样:
select (select count() from 表) - count()
from 表 where addtime between 1164038401 and 1511235339;
该查询会将子查询当做常数处理.

100w行数据,你内存又不够,分表吧,分成十个。
然后判断哪几个表在时间区间内有数据(查询第一个和最后一个数据即可判断)
最后只在这几个表中查询,汇总,这样大概能减少80%的内存占用和时间。
如果还嫌速度慢,那就大数据,多台服务器并发查询各自的子表,最后加和。

1、数量,@rift说的对,你做分页页数太多别人也不会翻这么多页

2、分页查询数据可以分为两步吧
1) select id from XXX where xxx=xx;
2) select * from XXX where id in (ids)
这样查询会好些

建议使用MySQL分区表,用addtime作为分区字段,不要任何索引。查询的时候带分区字段,确保查询扫描的分区表个数在一个很少的数量。这个方案不需要改动数据表结构和改动代码,实施成本低,效果很不错。

如果 id 是连续的,可以使用 id 作为分页依据

SELECT field FROM table_name WHERE `id` < num1 and `id` > num2

或者, id + limit 配合使用

SELECT field FROM table_name WHERE `id` > num LIMIT page_size

这样做的目的:

  • 大数据量时,LIMIT OFFSET 效率太低

  • id 唯一,自增,效率高于普通索引

你explain这条查询语句,由于count(*),type字段肯定是All,所以肯定是走全表的,但是如果你是count(id),应该会是ref,因为addtime你加索引了。

select查询的时候尽量不要使用*
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题