1、查询根据业务需求处理
举个例子:一张统计表,按小时/每个人统计,当经历过4年之后,它的数据量已经几千万了,老板明显感觉到现在首页内容刷新不出来了,需要改造,但业务场景是用户只关心几天的数据统计,需要看到月报/季度/半年/年报,我们就可以新建一张表,只存储用户一个月的数据,之后提供一个下载功能,如果要看以前的数据,可以提供下载任务,下载完成之后,用户可以点击下载按钮下载,月报/季度/半年/年报可以使用定时任务生成,完全OK。
但如果就是想要大数据分页查询
如:用户有一张大表,表中有个状态成功/失败,我需要把失败的找出来,重新执行,失败的一半,也是千万级,而且一直在变更,建一张小表处理问题明显也没有意义,而且为了不把所有的数据一次加载到内存中,我需要分页处理,这时候就涉及到了大数据分页(暂时我没想到怎么绕过这个场景)。
测试SQL执行效果

1、普通主键,如UUID

1、直接分页,执行失败,超时了

SELECT * FROM veh_parking LIMIT 20026664,50;

mysql 上亿数据count 很慢 mysql上亿数据查询_主键

2、子查询,查出来了但时间40223ms,一个分页耗时40多秒,基本没有意义

SELECT * FROM `veh_parking` WHERE `id` IN (SELECT id FROM (SELECT id FROM veh_parking LIMIT 20026664,50) a);

mysql 上亿数据count 很慢 mysql上亿数据查询_mysql_02

3、主键连接,耗时32376ms

SELECT b.* FROM `veh_parking` b INNER JOIN (SELECT id FROM (SELECT id FROM veh_parking LIMIT 20026664,50) a) a ON a.id = b.id

mysql 上亿数据count 很慢 mysql上亿数据查询_mysql_03


2、修改主键为自增主键1200w条数据

1、子查询,查出来了但时间20562ms,一个分页耗时20.562多秒,基本没变

SELECT * FROM `veh_parking` WHERE `id` IN (SELECT id FROM (SELECT id FROM veh_parking LIMIT 10000000,50) a);

mysql 上亿数据count 很慢 mysql上亿数据查询_主键_04

2、 先查出最大ID和最小ID,之后Between,查询一个ID用了4秒多,也不适用

SELECT id FROM (SELECT id FROM veh_parking LIMIT 10000000,1) a)

mysql 上亿数据count 很慢 mysql上亿数据查询_主键_05

3、直接Between ID,后面的值不存在,数据查询会存在问题,不符合后面的条件会把前面符合的数据去掉,且用时8s多也不适用

SELECT b.* FROM `veh_parking` b 
WHERE 
b.id> (SELECT id FROM (SELECT id FROM veh_parking LIMIT 10000000,1) a)
AND 
 b.id< (SELECT id FROM (SELECT id FROM veh_parking LIMIT 10000050,1) a)

mysql 上亿数据count 很慢 mysql上亿数据查询_mysql 上亿数据count 很慢_06

3、主键连接,耗时4613ms,4.6s

SELECT b.* FROM `veh_parking` b INNER JOIN (SELECT id FROM (SELECT id FROM veh_parking LIMIT 10000000,50) a) a ON a.id = b.id

mysql 上亿数据count 很慢 mysql上亿数据查询_mysql 上亿数据count 很慢_07

4、直接用子查询耗时4.619s,跟JOIN差不多

SELECT b.* FROM `veh_parking` b WHERE id > (SELECT id FROM (SELECT id FROM veh_parking LIMIT 10000000,1) a) LIMIT 50;

mysql 上亿数据count 很慢 mysql上亿数据查询_mysql_08

5、使用同一个子查询,控制分页条数,50条和5000条耗时差不多,所以可以使用借助代码缓存,一般数据的变更肯定不会是几年前的,即使有,缓存也是有失效期的,也需要严格控制缓存数据的多少

SELECT b.* FROM `veh_parking` b WHERE id > (SELECT id FROM (SELECT id FROM veh_parking LIMIT 10000000,1) a) LIMIT 5000;

mysql 上亿数据count 很慢 mysql上亿数据查询_mysql 上亿数据count 很慢_09

调试效果
1、使用递增主键,充分利用Mysql B+tree索引的范围查询的优势;
2、先通过只查询获取所有有效的ID(一遍查询,分页数据不会太大,字段只有一个)之后通过主键索引取值;
3、根据业务实际情况控制分页大小,借助缓存减少查询频率,普通分页,一次50条,这里一次查询5000条,时间也是相同,但总的耗时就变成了4.6/100=0.046s,这样就很OK了;

#Inner Join
SELECT b.* FROM `veh_parking` b INNER JOIN (SELECT id FROM (SELECT id FROM veh_parking LIMIT 10000000,50) a) a ON a.id = b.id
#子查询
SELECT b.* FROM `veh_parking` b WHERE id > (SELECT id FROM (SELECT id FROM veh_parking LIMIT 10000000,1) a) LIMIT 50;

后期继续调试,看看有没有更好的办法。