2014-01-26 4 views
1

У меня есть этот случай использование, где я должен делать инкрементное агрегирование данных, которая приходит вИнкрементальная агрегация: PL/SQL

У меня есть таблица , которая имеет следующие столбцы

id,insertion_time,key,col2,col3 

. я должен вычислить результат = col2 * col3 для каждой клавиши и найти максимум за час и поставить в другую таблицу B с колонками.

key,hour,max 

поэтому условие, если я собираюсь выполнить ту же процедуру через некоторое время, если новые данные были вставлены в таблице А, процедура должна перебрать только новые записи для обработки.

То, что я сделал до сих пор:

Я создал временную таблицу C для хранения последнего insertion_timestamp, который был обработан в last_timestamp. Каждое выполнение процедуры проверяет это значение и выберет только записи, которые имеют insertion_time > last_timestamp.

то прок будет сделать следующее:

  1. получить въездную last_timestamp из таблицы C
  2. выбрать максимальное значение col1 * col2 группы по ключевым и час где insertion_timestamp> lasttimestamp
  3. для каждый результат проверяет, присутствует ли пара для пары (ключ, час) в B

    a) если присутствует - обновить запись, если новое значение col1 * col2 больше существующего значения
    б) если нет, то добавить запись

Является ли это правильный способ делать инкрементную агрегацию в реляционных базах данных? Или есть лучший подход?

Thanks

+0

@eggyal Я не хочу, чтобы эта процедура выполнялась на каждой вставке. –

+0

Чтобы быть ясным, почему бы и нет? – eggyal

+0

не будет проблемой производительности? не будет ли лучше делать то же самое после кучи вставок? исправьте меня, если я ошибаюсь. –

ответ

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 и ЧАС в качестве символов в Oracle. Возможно, вы захотите выбрать разные имена.

Кроме того, если время, в течение которого ваши транзакции будут варьироваться, тогда время вставки, как видно из других транзакций, которые видят только зафиксированные данные, может не быть строго возрастающим. Таким образом, может быть хороший подход, чтобы немного отойти назад в прошлое, например:

WHERE insertion_time > l_last_timestamp - 3/24/3600 
+0

спасибо. Я попробую это .. –

Смежные вопросы