2016-03-30 5 views
0

У меня есть два набора данных, поступающих из внешнего источника - дата покупки клиента и последняя дата клика/открытия клиентом по электронной почте. Он хранится в двух таблицах PURCHASE_INTER и ACTIVITY_INTER соответственно. Данные о покупке несколько, и мне нужно забрать последнюю дату покупки. Но данные о деятельности уникальны для каждого клиента. Данные не зависят друг от друга, и другой набор данных может отсутствовать. Мы составили ниже запрос, который объединяет две таблицы, группирует их на основе person_id, который является идентификатором клиента, поступающего из внешнего источника, и получает последние даты, присоединяется к нашей таблице клиентов, чтобы получить электронную почту клиента и снова присоединиться к другой таблице где эти данные будут в конечном счете сохранены для того, чтобы знать, является ли это вставкой или операцией обновления. Не могли бы вы предложить, как я могу улучшить производительность этого запроса. Это ужасно медленно и занимает более 10 часов. В таблицах PURCHASE_INTER и ACTIVITY_INTER представлены миллионы записей.Улучшение производительности

SELECT INTER.*, C.ID AS CUSTOMER_ID, C.EMAIL AS CUSTOMER_EMAIL, LSI.ID AS INTERACTION_ID, ROW_NUMBER() OVER (ORDER BY PERSON_ID ASC) AS RN FROM (
    SELECT PERSON_ID    AS PERSON_ID, 
     MAX(LAST_CLICK_DATE) AS LAST_CLICK_DATE, 
     MAX(LAST_OPEN_DATE)  AS LAST_OPEN_DATE, 
     MAX(LAST_PURCHASE_DATE) AS LAST_PURCHASE_DATE 
    FROM (
    SELECT ACT.PERSON_ID AS PERSON_ID, 
      ACT.LAST_CLICK_DATE AS LAST_CLICK_DATE, 
      ACT.LAST_OPEN_DATE AS LAST_OPEN_DATE, 
      NULL AS LAST_PURCHASE_DATE 
    FROM ACTIVITY_INTER ACT 
    WHERE ACT.JOB_ID = 77318317 
    UNION 
    SELECT PUR.PERSON_ID AS PERSON_ID, 
      NULL AS LAST_CLICK_DATE, 
      NULL AS LAST_OPEN_DATE, 
      PUR.LAST_PURCHASE_DATE AS LAST_PURCHASE_DATE 
    FROM PURCHASE_INTER PUR 
    WHERE PUR.JOB_ID = 77318317 
    ) GROUP BY PERSON_ID 
) INTER LEFT JOIN CUSTOMER C ON INTER.PERSON_ID = C.PERSON_ID 
     LEFT JOIN INTERACTION LSI ON C.ID = LSI.CUSTOMER_ID; 
+0

Вам нужно удалить дубликаты, или вы можете использовать 'UNION ALL' вместо' UNION'? – jarlh

+0

Сколько записей соответствует заданию? –

+0

Вам действительно нужно предоставить столбец 'RN'? Это может быть дорого стоить, если вы возвращаете большое количество строк. –

ответ

5

Ваш запрос предлагает следующие показатели:

  • ACTIVITY_INTER(JOB_ID, PERSON_ID, LAST_CLICK_DATE, LAST_OPEN_DATE)
  • PURCHASE_INTER(JOB_ID, PERSON_ID, LAST_PURCHASE_DATE)
  • CUSTOMER(PERSON_ID)
  • INTERACTION(CUSTOMER_ID)

(для первого ТВт o, первый столбец более важен, чем два других, если количество совпадений не очень велико.)

Также измените UNION на UNION ALL. UNION берет накладные расходы для удаления дубликатов - и это невозможно (по крайней мере, между двумя подзапросами), потому что каждый подзапрос возвращает разные столбцы.

Кроме того, вы можете заменить первый подзапрос с full outer join:

SELECT COALESCE(a.PERSON_ID, p.PERSON_ID) as PERSON_ID, 
     a.LAST_CLICK_DATE, a.LAST_OPEN_DATE,p.LAST_PURCHASE_DATE 
FROM (SELECT ACT.PERSON_ID AS PERSON_ID, 
      MAX(ACT.LAST_CLICK_DATE) AS LAST_CLICK_DATE, 
      MAX(ACT.LAST_OPEN_DATE) AS LAST_OPEN_DATE 
     FROM ACTIVITY_INTER ACT 
     WHERE ACT.JOB_ID = 77318317 
     GROUP BY ACT.PERSON_ID 
    ) a FULL OUTER JOIN 
    (SELECT PUR.PERSON_ID AS PERSON_ID, 
      MAX(PUR.LAST_PURCHASE_DATE) AS LAST_PURCHASE_DATE 
     FROM PURCHASE_INTER PUR 
     WHERE PUR.JOB_ID = 77318317 
     GROUP BY PER.PERSON_ID 
    ) p 
    ON a.PERSON_ID = p.PERSON_ID 

Это дает Oracle больше возможностей для оптимизации, потому что агрегация осуществляется непосредственно на столах - делает индексы и лучше статистика доступный для обработки.

+0

Спасибо за вашу помощь по этому поводу. Это было действительно полезно. Я узнал много нового. –

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