我有一个要求,我必须从数据库中选择大约6000万条以上的记录。一旦我在ResultSet中拥有所有记录,那么我必须根据客户端要求(日期格式和数字格式)格式化一些列,然后我必须将所有记录写入文件(辅助存储器)。
最后,我将所有7个文件合并到一个文件中。
但整个过程需要6个小时才能完成。为了改进这个过程,我创建了7个7天的线程,所有线程都在编写单独的文件。
最后,我将所有7个文件合并到一个文件中。这个过程需要2个小时。但是我的程序将在1小时后转到OutOfMemory。
请为这个场景建议最好的设计,我应该使用一些缓存机制,如果是,那么哪一个以及如何?
注意:客户端不希望在数据库中更改任何内容,如创建索引或存储过程,他们不想触摸数据库。 提前谢谢。
答案 0 :(得分:4)
您是否需要在内存中记录所有记录以格式化它们?您可以尝试通过进程和文件直接传输记录。如果你甚至可以进一步打破查询,你可以开始处理结果,而你仍然可以检索它们。
根据您的数据库后端,他们可能有工具来帮助解决这个问题,例如SSIS for Sql Server 2005+。
修改强>
我是.net开发人员,所以让我建议我在.net中做什么,希望你可以转换成java方面的类似技术。
ADO.Net有一个DataReader,它是结果集的只进,只读(Firehose)光标。它在查询执行时返回数据。这是非常重要的。基本上,我的逻辑是:
IDataReader reader=GetTheDataReader(dayOfWeek);
while (reader.Read())
{
file.Write(formatRow(reader));
}
由于这是在我们返回行时执行,因此您不会阻止网络访问,我猜这是一个巨大的瓶颈。这里的关键是我们不会将任何内容存储在内存中很长时间,因为我们循环读取器会丢弃结果,文件会将行写入磁盘。
答案 1 :(得分:2)
我认为Josh的建议是:
你有循环,你当前浏览查询的所有结果记录(这里只使用伪代码):
while (rec = getNextRec() )
{
put in hash ...
}
for each rec in (hash)
{
format and save back in hash ...
}
for each rec in (hash)
{
write to a file ...
}
instead, do it like this:
while (rec = getNextRec() )
{
format fields ...
write to the file ...
}
那么你一次只能在内存中记录超过1条记录......而且你可以处理无限数量的记录。
答案 2 :(得分:1)
显然,一次读取6000万条记录会耗尽你所有的记忆 - 所以你不能这样做。 (即你的7线程模型)。一次读取一千万条记录就会耗尽所有时间 - 所以你也不能这样做(即你的初始读取文件模型)。
所以....你将不得不妥协并做两件事。
Josh没错 - 向你的数据库打开一个光标,只需以最简单,功能最强的方式一个接一个地读取下一条记录。您需要一个“firehose”游标(也称为只读,仅向前游标),因为它对数据库施加的负载最小。数据库不会让你更新记录,也不会在记录集中向后移动,这是你不想要的,所以它不需要处理记录的内存。
现在你有了这个光标,数据库一次给你一条记录 - 读它,然后把它写到一个文件(或几个文件),这应该很快完成。那么你的任务就是用正确的顺序将文件合并为1,这相对容易。
鉴于您必须处理的记录数量,我认为这是您的最佳解决方案。
但是......看到你到目前为止做得很好,为什么不减少线程数直到你在你的记忆限制范围内。批处理是隔夜运行的很多公司,这似乎只是这些过程中的另一个。
答案 3 :(得分:0)
取决于您使用的数据库,但如果它是SQL Server,我建议使用像SSIS这样的东西而不是编写程序。