【问题标题】:detecting when data has changed检测数据何时发生变化
【发布时间】:2011-03-17 18:49:22
【问题描述】:

好的,所以故事是这样的:

-- 我有很多特定格式的文件(相当大,大约 25GB),需要导入数据存储区

-- 这些文件不断更新数据,有时是新的,有时是相同的数据

-- 我正在尝试找出一种算法,如何检测文件中特定行的某些内容是否发生了变化,以最大限度地减少更新数据库所花费的时间

--它现在的工作方式是我每次都删除数据库中的所有数据,然后重新导入它,但这将不再有效,因为我需要一个时间戳来说明项目何时发生变化.

-- 文件包含字符串和数字(​​标题、订单、价格等)

我能想到的唯一解决方案是:

-- 计算数据库中每一行的哈希值,将其与文件中行的哈希值进行比较,如果它们不同,则更新数据库

-- 保留文件的 2 个副本,以前的和当前的,并在其上制作差异(这可能比更新数据库更快)并基于这些更新数据库。

由于数据量非常大到巨大,我现在有点别无选择。从长远来看,我会摆脱文件,数据将直接推入数据库,但问题仍然存在。

任何建议,将不胜感激。

【问题讨论】:

    标签: database algorithm scalability


    【解决方案1】:

    理解的问题定义

    假设您的文件包含

    ID,Name,Age
    1,Jim,20
    2,Tim,30
    3,Kim,40
    

    正如您所说,行可以添加/更新,因此文件变为

    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 查询或 1 个包含两个 sql 语句的批处理查询中仅插入/更新以上 2 条记录来更新数据库。

    我在这里做出以下假设

    • 您不能修改现有进程来创建文件。
    • 您正在使用一些批处理 [从文件读取 - 在内存中处理 - 在 DB 中写入] 上传数据库中的数据。

    将 Record [Name,Age] 的哈希值与 ID 存储在内存映射中,其中 ID 是键,值是哈希 [如果您需要可伸缩性,请使用 hazelcast ]。

    您的批处理框架加载数据[再次假设将一行文件视为一条记录],需要根据内存映射中的 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://www.hazelcast.com/

    http://static.springframework.org/spring-batch/

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      与其按需计算数据库中每一行的哈希值,不如存储哈希值?

      然后您可以只计算相关文件的哈希值并将其与数据库存储的哈希值进行比较。

      更新

      我想到的另一个选择是将上次修改的日期/时间信息存储在数据库中,然后将其与相关文件的信息进行比较。如果信息不能有意或无意更改,这应该可行。

      【讨论】:

      • 如果您要计算整个文件的哈希值与整个数据库的哈希值,这对我没有帮助。但是,如果您要在数据库中存储每行的哈希值,是的,这是我想到的解决方案之一。我只是想知道这是否比仅通过比较元素与元素来确定数据是否发生变化更快。
      • 我在那个文件中没有任何时间戳。
      • @hyperboreean,文件系统应该给你时间戳,但取决于 25GB 文件的结构,这可能有用也可能没用。我的回答中有更多建议。
      【解决方案3】:

      好吧,不管你使用什么,最坏的情况都是 O(n),这在 n ~ 25GB 的数据上并不是那么漂亮。

      除非您可以修改写入文件的进程。

      由于您不会一直更新所有 25GB,这是您节省周期的最大潜力。

      1.不要乱写
      你为什么不让写入数据的过程只追加?这样您将拥有更多数据,但您将拥有完整的历史记录,并且您可以跟踪您已经处理了哪些数据(您已经放入数据存储区中的数据)。

      2。如果您必须随机编写,请保留更改列表
      或者,如果您真的必须进行随机写入,您可以保留更新行的列表。然后可以像 #1 一样处理此列表,并且您可以跟踪您处理了哪些更改。如果您想节省一些空间,您可以保留数据更改的块列表(其中块是您定义的单位)。

      此外,您可以保留更改的块/行的校验和/哈希。然而,这可能不是很有趣——计算起来并不那么便宜,直接比较可能更便宜(如果你在写入期间有空闲的 CPU 周期,它可能会在以后为你节省一些阅读时间,YMMV)。

      注意事项

      • 只有当您可以调整将数据写入磁盘的过程时,#1 和#2 才有意义
      • 如果您无法修改写入 25GB 数据的进程,那么我看不出校验和/哈希如何提供帮助 - 您必须读取所有数据才能计算哈希(因为您不知道发生了什么变化) 这样您就可以在阅读时直接比较并得出要更新/添加(或直接更新/添加)的行列表
      • 使用 diff 算法可能不是最理想的,diff 算法不仅会查找更改的行,还会检查给定某些格式选项的两个文本文件之间的最小编辑距离。 (在diff 中,这可以使用 -H 或 --minimal 来控制以更慢或更快地工作,即搜索精确的最小解决方案或使用启发式算法,如果 iirc 该算法变为 O(n log n);这不是不好,但仍然比 O(n) 慢,如果您逐行进行直接比较,您可以使用 O(n))

      【讨论】:

        【解决方案4】:

        实际上,这是必须通过备份软件解决的问题,那么为什么不使用他们的一些标准解决方案呢? 最好的方法是挂钩 WriteFile 调用,以便您在每次更新时收到回调。这适用于二进制记录。

        我无法理解的事情:这些文件实际上是文本文件,不仅是附加的,而且是更新的?这是非常无效的(加上保留 2 个文件副本的想法,因为它会使文件缓存工作更糟)。

        【讨论】:

          猜你喜欢
          • 2016-12-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-20
          • 2019-09-13
          • 1970-01-01
          相关资源
          最近更新 更多