好的,所以故事是这样的:
- 我有很多文件(非常大,大约25GB),这些文件采用特定格式,需要在数据存储区中导入
- 这些文件不断更新数据,有时是新的,有时是相同的数据
- 我试图弄清楚如何检测文件中特定行的某些内容是否发生变化的算法,以便最大限度地减少更新数据库所花费的时间
- 它现在的工作方式是我每次都丢弃数据库中的所有数据,然后重新导入它,但这不再适用,因为我需要一个项目更改时间的时间戳
- 文件包含字符串和数字(标题,订单,价格等)
我能想到的唯一解决方案是:
- 为数据库中的每一行计算一个哈希值,将其与文件中行的哈希值进行比较,如果它们不同则更新数据库
- 保留2个文件副本,前面的文件和当前文件,并在其上制作差异(这可能比更新数据库更快),并根据这些更新数据库。
由于数据量非常庞大,我现在已经没有选择了。从长远来看,我将摆脱文件,数据将直接推送到数据库,但问题仍然存在。
任何建议,将不胜感激。
答案 0 :(得分:3)
问题定义已理解。
假设您的文件包含
ID,Name,Age
1,Jim,20
2,Tim,30
3,Kim,40
如您所述,可以添加/更新Row,因此文件变为
ID,Name,Age
1,Jim,20 -- to be discarded
2,Tim,35 -- to be updated
3,Kim,40 -- to be discarded
4,Zim,30 -- to be inserted
现在要求通过在两个sql查询中插入/更新2个记录或者包含两个sql语句的1个批处理查询来更新数据库。
我在这里做假设
将记录[名称,年龄]的哈希值与ID存储在内存映射中,其中ID是键,值是哈希[如果需要可伸缩性,请使用hazelcast]。
您的Batch Framework加载数据[再次假设将一行文件视为一个记录],需要根据内存Map中的ID检查计算的哈希值。也可以使用批处理框架创建第一次创建用于阅读文件。
If (ID present)
--- compare hash
---found same then discard it
—found different create an update sql
In case ID not present in in-memory hash,create an insert sql and insert the hashvalue
您可以使用spring-batch和hazelcast进行并行处理,块处理和内存中数据分区。
http://static.springframework.org/spring-batch/
希望这会有所帮助。
答案 1 :(得分:1)
不是为了按需计算数据库中每一行的哈希值,而是为什么不存储哈希值呢?
然后你可以计算相关文件的哈希值,并将其与存储的数据库进行比较。
<强>更新强>:
我想到的另一个选择是将上次修改日期/时间信息存储在数据库中,然后将其与相关文件的信息进行比较。如果无法有意或无意地更改信息,这应该有效。
答案 2 :(得分:1)
无论你使用什么,最糟糕的情况都是O(n),在n~25GB的数据上并不是那么漂亮。
除非您可以修改写入文件的过程。
由于您没有一直更新所有25GB,这是您节省周期的最大潜力。
<强> 1。不要随便写
为什么不进行只写入数据的进程?这样您就可以获得更多数据,但是您将拥有完整的历史记录,并且可以跟踪已处理的数据(已放入数据存储区中的数据)。
<强> 2。如果必须随机写,请保留一份更改清单
或者,如果您真的必须进行随机写入,则可以保留更新行的列表。然后可以在#1中处理此列表,您可以跟踪您处理的更改。如果要保存一些空间,可以保留数据更改的块列表(块是您定义的单位)。
此外,您可以保留更改的块/行的校验和/哈希值。然而,这可能不是很有趣 - 计算起来并不便宜,直接比较可能更便宜(如果你在写作过程中有空闲的CPU周期,可能会节省一些阅读时间,YMMV)。
注意
答案 3 :(得分:0)
实际上这是一个必须由备份软件解决的问题,为什么不使用他们的一些标准解决方案呢? 最好的方法是挂钩WriteFile调用,这样你就可以在每次更新时收到回调。这对二进制记录非常有用。
我无法理解的东西:文件实际上是文本文件,不只是附加,而是更新?这是非常无效的(连同保留2个文件副本的想法,因为它会使文件缓存工作更糟糕。)