【问题标题】:Cron job to remove logically redundant entries in Postgres SQL用于删除 Postgresql 中逻辑冗余条目的 Cron 作业
【发布时间】:2019-10-29 03:05:03
【问题描述】:

我需要从具有超过 2 亿条记录的 Postgres SQL 表中删除记录。该表没有任何主键。

示例表(书签为表名)内容如下:

systemId     filename           mindatetime                 maxdatetime
  70277     monitor_1.dat   2019-04-21 08:00:00 AM      2019-04-21 03:10:00 PM
  10006     monitor_2.dat   2019-04-25 10:00:00 AM      2019-04-25 11:30:00 AM
  10006     monitor_3.dat   2019-04-28 08:00:00 AM      2019-04-28 10:00:00 AM
  10006     monitor_3.dat   2019-04-28 09:00:00 AM      2019-04-28 11:00:00 AM
  10006     monitor_3.dat   2019-04-28 07:00:00 AM      2019-04-28 04:00:00 PM
  8368      monitor_1.dat   2019-05-21 11:00:00 AM      2019-05-21 11:30:00 AM
  8368      monitor_7.dat   2019-05-21 06:00:00 AM      2019-05-21 11:00:00 AM
  8368      monitor_5.dat   2019-05-23 08:00:00 AM      2019-05-23 10:00:00 AM
  72777     monitor_4.dat   2019-04-28 09:00:00 AM      2019-04-29 11:00:00 AM
  72777     monitor_4.dat   2019-04-28 11:00:00 AM      2019-04-29 18:00:00 PM
  72777     monitor_4.dat   2019-04-28 09:30:00 AM      2019-04-29 23:00:00 PM
  12345     monitor_5.dat   2019-04-28 07:00:00 AM      2019-04-28 10:00:00 AM
  12345     monitor_5.dat   2019-04-28 02:00:00 PM      2019-04-28 06:00:00 PM
  12345     monitor_5.dat   2019-04-28 09:00:00 AM      2019-04-28 03:00:00 PM
  10006     monitor_8.dat   2019-04-28 09:00:00 AM      2019-04-29 09:00:00 AM
  10006     monitor_8.dat   2019-04-29 09:01:00 AM      2019-04-30 10:00:00 AM
  10006     monitor_8.dat   2019-04-30 10:01:00 AM      2019-04-30 11:00:00 AM
  10006     monitor_8.dat   2019-05-12 07:00:10.001 AM  2019-05-13 10:00:10.000 AM
  10006     monitor_8.dat   2019-05-15 09:30:10.001 AM  2019-05-18 11:30:10.000 AM

cron 作业应该按照给定的时间表运行,以删除逻辑上冗余的记录。

为了解释这一点,让我们以 systemId '10006' 为例,其中文件名为 'monitor_3.dat' 有 3 个条目,最小和最大日期时间戳为同一天。

从逻辑上讲,我们可以删除具有 mindatetime 08:00:00 AM 和 09:00:00 AM、maxdatetime 10:00:00 AM、11:00:00 AM 的条目,因为该间隔被另一个条目覆盖mindatetime 为上午 7 点,maxdatetime 为下午 4 点。

因此,这些条目将落在此间隔内,作业应在整个表中识别此类条目并将其删除。

在这种情况下我的结果输出表内容应该是:

 systemId    filename           mindatetime                 maxdatetime
  70277     monitor_1.dat   2019-04-21 08:00:00 AM      2019-04-21 03:10:00 PM
  10006     monitor_2.dat   2019-04-25 10:00:00 AM      2019-04-25 11:30:00 AM
  10006     monitor_3.dat   2019-04-28 07:00:00 AM      2019-04-28 04:00:00 PM
  8368      monitor_1.dat   2019-05-21 11:00:00 AM      2019-05-21 11:30:00 AM
  8368      monitor_7.dat   2019-05-21 06:00:00 AM      2019-05-21 11:00:00 AM
  8368      monitor_5.dat   2019-05-23 08:00:00 AM      2019-05-23 10:00:00 AM
  72777     monitor_4.dat   2019-04-28 09:00:00 AM      2019-04-29 23:00:00 PM
  12345     monitor_5.dat   2019-04-28 07:00:00 AM      2019-04-28 06:00:00 PM
  10006     monitor_8.dat   2019-04-28 09:00:00 AM      2019-04-30 11:00:00 AM
  10006     monitor_8.dat   2019-05-12 07:00:10.001 AM  2019-05-13 10:00:10.000 AM
  10006     monitor_8.dat   2019-05-15 09:30:10.001 AM  2019-05-18 11:30:10.000 AM

磁盘上的表大小超过 20Gb,所以我正在探索编写一个 sql 过程或作业来实现这一点,但没有取得太大进展。对于克服这种复杂情况有什么想法或建议吗?

【问题讨论】:

    标签: java postgresql stored-procedures jdbc job-scheduling


    【解决方案1】:

    您可以使用 tsranges 来查找重叠。如果有唯一键,查询会更简单一些,如果有重复的行,您可能会遇到问题,但基本思路如下:

    -- The rows to be deleted:
    
    select * from bookmark WHERE exists
    (select 1 from bookmark bm2
      WHERE bm2.systemid = bookmark.systemid
       AND  bm2.filename = bookmark.filename
       AND  (bookmark.systemid, bookmark.filename, bookmark.mindatetime, bookmark.maxdatetime) IS DISTINCT FROM (bm2.systemid, bm2.filename, bm2.mindatetime, bm2.maxdatetime)
       AND tsrange(bookmark.mindatetime, bookmark.maxdatetime, '[]') <@ tsrange(bm2.mindatetime, bm2.maxdatetime, '[]')
    );
     systemid |   filename    |     mindatetime     |     maxdatetime
    ----------+---------------+---------------------+---------------------
        10006 | monitor_3.dat | 2019-04-28 08:00:00 | 2019-04-28 10:00:00
        10006 | monitor_3.dat | 2019-04-28 09:00:00 | 2019-04-28 11:00:00
        72777 | monitor_4.dat | 2019-04-28 11:00:00 | 2019-04-29 18:00:00
    
    
    -- Delete them like so:
    
    delete from bookmark WHERE exists
    (select 1 from bookmark bm2
      WHERE bm2.systemid = bookmark.systemid
       AND  bm2.filename = bookmark.filename
       AND  (bookmark.systemid, bookmark.filename, bookmark.mindatetime, bookmark.maxdatetime) IS DISTINCT FROM (bm2.systemid, bm2.filename, bm2.mindatetime, bm2.maxdatetime)
       AND tsrange(bookmark.mindatetime, bookmark.maxdatetime, '[]') <@ tsrange(bm2.mindatetime, bm2.maxdatetime, '[]')
    );
    

    请注意,由于数据中的拼写错误,这与您的预期输出不完全匹配。这两行不重叠:

    72777 | monitor_4.dat | 2019-04-28 09:00:00 | 2019-04-29 11:00:00
    72777 | monitor_4.dat | 2019-04-28 09:30:00 | 2019-04-29 23:00:00
    

    除非您真的要更新和删除?在这种情况下,您最好的选择可能是创建一个新表并重命名它:

    CREATE TABLE bookmark_load AS 
      SELECT systemid, filename, min(mindatetime), max(maxdatetime)
      FROM bookmark
      GROUP BY systemid, filename;
    
    ALTER TABLE bookmark RENAME TO bookmark_old;
    ALTER TABLE bookmark_load RENAME TO bookmark;
    

    当然,您不能在执行此操作时将新数据插入书签。

    【讨论】:

    • 我已经用另一个您的代码失败的场景编辑了这个问题。我需要给定系统 ID 和文件名的最小和最大日期时间的逻辑间隔。
    • 我不明白结果表中如何包含源表中不存在的行。我以为你只是想删除行。是不是打错字了?
    • 对于我在问题本身中更新的一组输入,SQL 查询再次失败。基本上当时间范围不是自包含的时候。
    • 预期输出中的哪一行与我发布的最终查询不匹配?输出在我看来完全一样。
    • systemid 为“12345”的那个我后来添加了这个,因为查询失败了
    猜你喜欢
    • 2018-01-19
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    • 2012-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多