海量数据分页,已经无法使用数据库自带的分页机制,比如MySQL 的 Limit ,这会导致严重的性能问题
1.问题的提出
在软件开发中,大数据量的查询是一个常见的问题,经常会遇到对大量数据进行查询的场景。
常见的对大数据量查询的解决方案有以下两种:
(1)、将全部数据先查询到内存中,然后在内存中进行分页,这种方式对内存占用较大,必须限制一次查询的数据量。
(2)、采用存储过程在数据库中进行分页,这种方式对数据库的依赖较大,不同的数据库实现机制不通,并且查询效率不够理想。以上两种方式对用户来说都不够友好。
2.解决思路
通过在待查询的数据库表上增加一个用于查询的自增长字段,然后采用该字段进行分页查询,可以很好地解决这个问题。下面举例说明这种分页查询方案。
(1)、在待查询的表格上增加一个long型的自增长列,取名为“queryId” 主键增长
先按照大小顺序的倒序查出所有的queryId,
语句如下:select queryId from test_table where order by queryId desc
因为只是查询queryId字段,即使表格中的数据量很大,该查询也会很快得到结果。然后将得到的queryId保存在应用服务器的一个数组中。
用户在客户端进行翻页操作时,客户端将待查询的页号作为参数传递给应用服务器,服务器通过页号和queyId数组算出待查询的queyId最大和最小值,然后进行查询。
算出queyId最大和最小值的算法如下,其中page为待查询的页号,pageSize为每页的大小,queryIds为第二步生成的queryId数组:
int startRow = (page - 1) * pageSize
int endRow = page * pageSize - 1;
if (endRow >=queryIds.length)
{
endRow = this.queryIds.length - 1;
}
long startId =queryIds[startRow];
long endId =queryIds[endRow];
查询语句如下:
String sql = "select * from test_table" + 查询条件 + "(queryId <= " + startId + " and queryId >= " + endId + ")";
3.效果评价
该分页查询方法对所有数据库都适用,对应用服务器、数据库服务器、查询客户端的cpu和内存占用都较低,查询速度较快,是一个较为理想的分页查询实现方案。经过测试,查询4百万条数据,可以在3分钟内显示出首页数据,以后每一次翻页操作基本在2秒以内。内存和cpu占用无明显增长。
4. 对于大数据,我认为数据分区、分成多个表、增加内存、换更好的机器都是物理上的,当然她带来的速度的改善是有的。
在软的方面,最有效和可行的办法是优化数据库结构和索引,对于优化数据库有根据事务型和数据仓库型分为两个方面
偏重事务需要插入、更新速度快,所以一般这样的表索引比较少,字段数目也少
数据仓库需要查询速度快,他一般会根据查询可能出现的条件建立所有的索引
在大数据量的数据库中,一旦某个查询不能完全利用索引,就会形成表扫描。这是最坏的情况
我一般是分成两个库,一个处理事务,一个处理查询,
总的来说,只有才所有软的手段不能解决问题的情况下才采用物理的方法。