【问题标题】:Incremental aggregation : PL/SQL增量聚合:PL/SQL
【发布时间】:2014-01-26 10:05:57
【问题描述】:

我有这个用例,我必须对传入的数据进行增量聚合。

我有一个表 A,其中包含以下列

id,insertion_time,key,col2,col3

我必须为每个键计算结果 = col2*col3 并在一小时内找到最大值,然后将其放入另一个带有列的表 B

key,hour,max

所以条件是,如果我要在一段时间后运行相同的过程,如果新数据已插入到表 A 中,则该过程应该只循环处理要处理的新记录。

到目前为止我做了什么:

我创建了一个临时表 C 来存储最后一个被处理为last_timestampinsertion_timestamp。每个过程执行都会检查这个值,并且只选择具有insertion_time > last_timestamp 的条目。

那么 proc 将执行以下操作:

  1. 从表 C 中获取条目 last_timestamp

  2. 通过key和hour选择col1*col2组的最大值 where insert_timestamp > lasttimestamp

  3. 对于每个结果,检查 B 中是否存在 (key,hour) 对的条目

    a) 如果存在 - 如果新的 col1*col2 值大于现有值,则更新条目
    b) 如果没有,请插入条目

这是在关系数据库中进行增量聚合的正确方法吗?或者有没有更好的方法?

谢谢

【问题讨论】:

  • @eggyal 我不希望这个过程在每次插入时都运行。
  • 说清楚,为什么不呢?
  • 不会是性能问题吗?在一堆插入之后做同样的事情会更好吗?如果我错了,请纠正我。
  • 取决于您的性能要求。使用适当的索引,将 B 更新为其现有值和新插入记录的倍数中的较大者是一项简单的任务;而从 A 上的聚合更新 B 以找到给定小时内所有记录的最大倍数相对更复杂。但是,如果您需要插入时的每一滴性能,并且有能力离线更新 B,那么也许值得考虑。就个人而言,我会使用触发器,直到性能另有规定:记住 Knuth 的格言,“过早的优化是万恶之源”。
  • 谢谢。我可能会测试这两种情况,看看哪个更好。

标签: oracle stored-procedures plsql


【解决方案1】:

是的,您的方法似乎没问题。我想不出任何其他的会更好:

PROCEDURE CALC_HOURLY_MAX
IS
    l_last_timestamp DATE;
    l_max_insertion_time DATE;
    l_value NUMBER;

BEGIN
   SELECT last_timestamp into l_last_timestamp FROM ...;

   FOR r IN (
       SELECT MAX(col2 * col3) max_value, key,
         TRUNC(insertion_time, 'HH24') hour,
         MAX(insertion_time) max_insertion_time
       FROM A
       WHERE insertion_time > l_last_timestamp
       GROUP BY key, TRUNC(insertion_time, 'HH24')
   ) LOOP

       BEGIN
         SELECT max into l_value FROM B where key = r.key and hour = r.hour;

         IF l_value < r.max_value THEN
            UPDATE B set max = r.max_value where key = r.key and hour = r.hour;
         END IF;

       EXCEPTION
         WHEN NO_DATA_FOUND THEN
           INSERT INTO B (key, hour, max) VALUES(r.key, r.hour, r.max_value);

       END;

       IF l_max_insertion_time  is null OR l_max_insertion_time < r.max_insertion_time THEN
         l_max_insertion_time := r.max_insertion_time;
       END IF;
   END LOOP;

   -- store highest processed insertion time
   UPDATE XX SET last_timestamp = l_max_insertion_time WHERE ...;
END;

请注意,此代码可能无法编译为列名 MAX 和 HOUR 作为 Oracle 中的符号。您可能想选择不同的名称。

此外,如果您的事务花费的时间发生变化,那么插入时间(从仅查看已提交数据的其他事务中可以看出)可能不会严格增加。因此,选择更远的过去可能是一个好方法,例如:

WHERE insertion_time > l_last_timestamp - 3 / 24 / 3600

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-23
    • 1970-01-01
    • 2021-08-19
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    相关资源
    最近更新 更多