Перепишите запрос для использования функций Analyti c - PullRequest
4 голосов
/ 17 марта 2020

У меня есть таблица событий, которая регистрирует I nsert, U pdate и D elete событий. См MWE ее: http://sqlfiddle.com/#! 4 / 6c2cb1 / 1

DDL Заявление

CREATE TABLE "EVENTS" 
   (
    "EVENT_ID" VARCHAR2(30 CHAR), --Name of the Event
    "EVENT_LOCATION" VARCHAR2(60 CHAR), --Location on which the event occured
    "EVENT_TRIGGER" VARCHAR2(2 CHAR),  --Trigger which protocolled the event (I,U or D)
    "EVENT_CHANGE_ID" NUMBER,  --Unique Sequence Number
    "EVENT_CHANGE_DATE" DATE DEFAULT SYSTIMESTAMP
   );

INSERT INTO EVENTS (EVENT_ID,EVENT_LOCATION,EVENT_TRIGGER,EVENT_CHANGE_ID,EVENT_CHANGE_DATE) 
VALUES ('EVENT1','LOC1','I',1,SYSTIMESTAMP-1);
INSERT INTO EVENTS (EVENT_ID,EVENT_LOCATION,EVENT_TRIGGER,EVENT_CHANGE_ID,EVENT_CHANGE_DATE) 
VALUES ('EVENT1','LOC2','U',11,SYSTIMESTAMP-1);
INSERT INTO EVENTS (EVENT_ID,EVENT_LOCATION,EVENT_TRIGGER,EVENT_CHANGE_ID,EVENT_CHANGE_DATE) 
VALUES ('EVENT1','LOC4','U',117,SYSTIMESTAMP-1);
INSERT INTO EVENTS (EVENT_ID,EVENT_LOCATION,EVENT_TRIGGER,EVENT_CHANGE_ID,EVENT_CHANGE_DATE) 
VALUES ('EVENT1','LOC7','D',1430,SYSTIMESTAMP-1);

INSERT INTO EVENTS (EVENT_ID,EVENT_LOCATION,EVENT_TRIGGER,EVENT_CHANGE_ID,EVENT_CHANGE_DATE) 
VALUES ('EVENT2','LOC1','I',2,SYSTIMESTAMP-1/48);
INSERT INTO EVENTS (EVENT_ID,EVENT_LOCATION,EVENT_TRIGGER,EVENT_CHANGE_ID,EVENT_CHANGE_DATE) 
VALUES ('EVENT2','LOC2','U',131,SYSTIMESTAMP-1/48);
INSERT INTO EVENTS (EVENT_ID,EVENT_LOCATION,EVENT_TRIGGER,EVENT_CHANGE_ID,EVENT_CHANGE_DATE) 
VALUES ('EVENT2','LOC5','D',11337,SYSTIMESTAMP-1/48);
INSERT INTO EVENTS (EVENT_ID,EVENT_LOCATION,EVENT_TRIGGER,EVENT_CHANGE_ID,EVENT_CHANGE_DATE) 
VALUES ('EVENT2','LOC7','D',14430,SYSTIMESTAMP-1/48);

Я хочу определить количество событий, которые были I вставлено в LOC1 и D , выбрано в LOC7 без каких-либо промежуточных элементов D .

SELECT COUNT(*) AS QTY, TRUNC(A.EVENT_CHANGE_DATE) AS DAY
FROM (
    SELECT EVENT_ID, EVENT_CHANGE_ID, EVENT_CHANGE_DATE FROM EVENTS WHERE EVENT_TRIGGER = 'I' AND EVENT_LOCATION = 'LOC1'
    ) A,
    (SELECT EVENT_ID, EVENT_CHANGE_ID, EVENT_CHANGE_DATE FROM EVENTS WHERE EVENT_TRIGGER = 'D' AND EVENT_LOCATION = 'LOC7')
    B
WHERE B.EVENT_CHANGE_ID > A.EVENT_CHANGE_ID AND A.EVENT_ID = B.EVENT_ID
    AND not exists (SELECT EVENT_ID, EVENT_CHANGE_ID, EVENT_CHANGE_DATE FROM EVENTS WHERE EVENT_TRIGGER = 'D' AND EVENT_CHANGE_ID > A.EVENT_CHANGE_ID AND EVENT_CHANGE_ID < B.EVENT_CHANGE_ID and EVENT_ID = A.EVENT_ID) 
group by TRUNC(A.EVENT_CHANGE_DATE)
ORDER BY TRUNC(A.EVENT_CHANGE_DATE);

Мой наивный подход работает, однако мне интересно, можно ли переписать этот запрос, используя функции analyti c. Исходные таблицы содержат до 1 млн. Записей, а 3-кратное полное сканирование таблицы - это не go относительно времени выполнения и производительности.

Возможно ли даже сделать этот запрос более эффективным с помощью аналитических функций?

Ответы [ 4 ]

2 голосов
/ 17 марта 2020

Использование только функции classi c analyti c.

Фильтрация только соответствующих событий

(EVENT_TRIGGER = 'I' AND EVENT_LOCATION = 'LOC1')  OR  -- only LOC1 inserts
 EVENT_TRIGGER = 'D')                                  -- all deletes

Затем LEAD следующий D выбор и проверка местоположения

with evnt as
(
  select EVENT_ID, EVENT_LOCATION, EVENT_TRIGGER, EVENT_CHANGE_DATE,
    lead(EVENT_TRIGGER) over (PARTITION BY EVENT_ID 
                                  order by EVENT_CHANGE_DATE, EVENT_LOCATION)
      as EVENT_TRIGGER_LEAD,
    lead(EVENT_LOCATION) over (PARTITION BY EVENT_ID
                                   order by EVENT_CHANGE_DATE, EVENT_LOCATION)
      as EVENT_LOCATION_LEAD
  from EVENTS
  where (EVENT_TRIGGER = 'I' AND EVENT_LOCATION = 'LOC1') OR EVENT_TRIGGER = 'D'
)
select 
  EVENT_ID, EVENT_LOCATION, EVENT_TRIGGER, EVENT_CHANGE_DATE,
  EVENT_TRIGGER_LEAD, EVENT_LOCATION_LEAD
from evnt
where EVENT_TRIGGER = 'I'
  and EVENT_TRIGGER_LEAD = 'D' 
  and EVENT_LOCATION_LEAD = 'LOC7'
order by EVENT_ID, EVENT_CHANGE_DATE, EVENT_LOCATION;
2 голосов
/ 17 марта 2020

Это выглядит как подходящее для SQL сопоставления с образцом:

select * from events
match_recognize (
  partition by event_id
  order by event_change_date
  measures 
    count ( ins.* ) ins_count,
    min ( event_change_date ) dt
  pattern ( ins upd* del )
  define 
    ins as event_trigger = 'I' and event_location = 'LOC1',
    upd as event_trigger = 'U',
    del as event_trigger = 'D' and event_location = 'LOC7'
);

INS_COUNT    DT                     
           1 16-MAR-2020 12:33:58 

Это ищет I (nserts) в LOC1, за которым следует D (elete) в LOC7, с любым числом U (pdates) между.

1 голос
/ 17 марта 2020

Вы можете использовать аналитическую функцию SUM, чтобы добавить 1 к результату, когда оно равно LOC1 и I, и добавить -1, когда оно равно D, тогда конечным результатом будет запись, имеющая sum = 0 и location as LOC7.

см. Ответ:

SQL> SELECT EVENT_ID FROM
  2      ( SELECT SUM(CASE
  3                  WHEN EVENT_LOCATION = 'LOC1' AND EVENT_TRIGGER = 'I' THEN 1
  4                  WHEN EVENT_TRIGGER = 'D' THEN - 1
  5               END) OVER( PARTITION BY EVENT_ID ORDER BY EVENT_CHANGE_DATE ) AS SM,
  6               T.*
  7          FROM EVENTS T
  8      ) T
  9  WHERE EVENT_LOCATION = 'LOC7' AND SM = 0;

EVENT_ID
------------
EVENT1

SQL>

Ура !!

0 голосов
/ 17 марта 2020

Использование аналитической функции LEAD:

SELECT COUNT(*) as qty,
       TRUNC(event_change_date)day  
       FROM(
            SELECT
                event_location,
                event_trigger,
                event_change_date,
                lead(event_trigger) 
                  OVER(PARTITION BY trunc(event_change_date) 
                       ORDER BY to_number(substr(event_location, - 1, 1))) rn 
            FROM events
) WHERE event_trigger <> 'D'
AND rn <> 'D'
AND event_trigger = rn
GROUP BY trunc(event_change_date);

QTY        DAY     
---------- --------
         1 16-03-20

Logi c:

  1. Группируйте события каждого дня и упорядочивайте их по местоположению от 1 до 7, используя SUBSTR, и получайте число от обратной строки.
  2. Используйте LEAD для сравнения event_trigger с его лидерством.
  3. Event_trigger в группе PARTITIONED каждой даты не должен иметь DELETE от 1 до 7.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...