我正在开发一个 java 程序,它实际上从 postgresql 数据库中检索元组并使用它们做一些工作。我将每个元组表示为 String
的 Vector
,并将完整的元组集 (resultSet) 表示为元组的 vector 。
Vector<String> tuple;
Vector<Vector<String>> resultSet;
在我的应用程序中,我需要处理数百万个元组。这是一个简单的基准测试,它通过简单地读取结果集中的 X 个元组然后打印结果集大小、第一个和最后一个元组来模拟我的程序。
benchmark 考虑使用 vector 和 arrayList 来表示元组
List<String> tuple;
List<List<String>> resultSet;
基准程序代码
import java.util.Vector;
import java.util.List;
import java.util.ArrayList;
public class VectorVSarrayList {
public static void loadDataInVector(Integer size){
Vector<Vector<String>> r = new Vector<Vector<String>>();
Vector<String> tuple = new Vector<String>();
startTimer();
for(Integer i = 0; i < size; i++){
tuple = new Vector<String>();
for(int j = 0; j < 3; j ++)
tuple.add(i.toString() + " tuple "+j);
r.add(tuple);
}
endTimer("vector size " + r.size() + " first element : " + r.get(0).get(0) + ", and last element : " + r.get(r.size()-1).get(0));
r.clear();
}
public static void loadDataInArrayList(Integer size){
List<List<String>> r = new ArrayList<List<String>>();
List<String> tuple = new ArrayList<String>();
startTimer();
for(Integer i = 0; i < size; i++){
tuple = new ArrayList<String>();
for(int j = 0; j < 3; j ++)
tuple.add(i.toString() + " tuple "+j);
r.add(tuple);
}
endTimer("array size " + r.size() + " first element : " + r.get(0).get(0) + ", and last element : " + r.get(r.size()-1).get(0));
r.clear();
}
public static void main(String [] args){
Integer size = Integer.parseInt(args[0]);
loadDataInArrayList(size);
loadDataInVector(size);
loadDataInArrayList(size);
loadDataInVector(size);
}
private static long startTime = 0;
private static long endTime = 0;
public static void startTimer(){
startTime = System.currentTimeMillis();
}
public static void endTimer(String log){
endTime = System.currentTimeMillis();
System.out.println(log + ", " + (endTime - startTime) + ", ms");
}
}
我已经运行了基准测试来处理 1 和 1000 万个元组,Java 堆大小扩展到 2G,这是结果
> time java -Xmx2g VectorVSarrayList 1000000
array size 1000000 first element : 0 tuple 0, and last element : 999999 tuple 0, 1642, ms
vector size 1000000 first element : 0 tuple 0, and last element : 999999 tuple 0, 1075, ms
array size 1000000 first element : 0 tuple 0, and last element : 999999 tuple 0, 1625, ms
vector size 1000000 first element : 0 tuple 0, and last element : 999999 tuple 0, 308, ms
real 0m4.829s
user 0m14.849s
sys 0m0.500s
> time java -Xmx2g VectorVSarrayList 10000000
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at VectorVSarrayList.loadDataInArrayList(VectorVSarrayList.java:72)
at VectorVSarrayList.main(VectorVSarrayList.java:28)
real 6m12.708s
user 22m57.662s
sys 0m6.200s
这些结果表明,即使只有 1000 万个元组,我也将花费至少 6 分钟(而 100 万个元组需要 4 秒)并最终运行 OutOfMemory
OS : Ubuntu 12.04
RAM : 6 GB
processor : Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz
是否有更好的方法(更好的集合类型或更好的实践)来完成此类工作?
最佳答案
根据“一些工作”的含义,您可以优化这个问题,我将其理解为对数据库中的结果进行分组。
显然,您可以使用更高效的数据结构,这样不会使您的堆溢出。但是每次数据更改(相关)时,这些都需要维护。在上述情况下,创建初始大小为 3 的 ArrayList 或更好地使用 LinkedList。
另一种方法是让数据库已经准备好数据,以便此准备支持您的操作。喜欢
- 按您的组键排序数据(在数据库中)
- 迭代器遍历数据,只要组键相同就填充A vector
- 当组键更改时,对分组序列进行一些处理(例如存储或打印出第一个、最后一个和大小或其他任何内容)并仅存储该序列的相关事实。
- 数据完成后,处理每个序列的结果,比如聚合它们
这种方法称为 MapReduce,这里映射是在数据库中(虚拟地)完成的,而缩减是在您的程序中完成的。
关于java - 如何在 java 中有效地处理数百万元组的集合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22854086/