学过操作系统的人都知道请求分页存储管理方法,这也是为啥1G内存的计算机能够处理超过1G的数据量的原因。最近做项目遇到大数据量处理的问题,结合请求分页算法的原来,成功的处理了一亿条数据。到这儿来分享一下给大家:
首先是一亿条数据的存储问题,这么多数据放在内存里,肯定会溢出的,更不用提数据的处理了。所以肯定要借助于磁盘存储了。结合操作系统的文件系统里的层次索引结构,我们可以设计出高效的存储方法。具体的算法思想如下:
先将一亿条数据分成10000组,那么1组有10000条数据。正常内存里放着几个组,内存里存放的组的上限比如说是10个,也就是内存最多放10组。如果要到的数据不在内存里,那么从磁盘里面取出来。假如当前内存里已经有10组了,那么就先要将最不活跃的那一组先从内存里销毁,再取出目标组代替之。我们需要建立一个关于组的索引,同时组内也要有一个索引。那么我们可以简单的通过组索引和组内索引,轻松的找到目标的位置。一般情况下,我们可以把一个组写入一个文件。
我们可以更近一步,设计出更多层次的结构。比如说:将10亿条数据分成10块,1块就是1亿条,再将一块分成10000组,一组10000条。这就是三层索引了。
我们需要注意的是:组的大小是个未知的值。如果组的大小设置的过小,那么组的数量会很多,实际的文件就会很多,假如有个遍历操作,需要建立的输入输出流数量就是文件的数量,那么重复的建立输入输出流就会非常的耗时耗资源。假如组的大小设置的过大,那么读取一个组的时候,将组文件转化成指定的数据结构就会很耗时。那么,获取一个给定值时,就会因此很慢。所以,组的大小,需要实际中根据性能要求去反复的调试、实验,以获取一个最佳值。
个人测试了好久,觉得最影响性能还是I/O操作。所以,应该考虑一些高效的I/O操作方法。比如说字节缓冲机制等等。
不多说:最简单的Java代码实现如下:
/**
* 双层次索引顺序表
*
* 索引结果请不要用Iterator,用它效率非常差,Iterator是针对链表结构的,比如说LinkedList
* @author zhou@since 2012-8-7下午5:33:00
*/
public class TwoLevelArrayList extends AbstractList {
/**
* ArrayList<Group>
*/
private ArrayList groupArray;// 第一层次
/**
* 当前的group,它都是alive
*/
private Group currentGroup;
private int currentGroupIndex;
private String cacheFilePath;
private static final String FILE_EXTENSION = ".part";
/**
* cacheFile是个文件夹
*
* @param parentFile
*/
public TwoLevelArrayList(File parentFile) {
if (!parentFile.exists()) {
parentFile.mkdirs();
}
if (!parentFile.isDirectory()) {
parentFile.delete();
throw new UnsupportedOperationException("cacheFile必须是个文件夹!");
}
String id = UUID.randomUUID().toString();// 生成一个临时文件夹
cacheFilePath = parentFile.getAbsolutePath()