Oracle 12c - эффективный способ присоединиться к записи максимальной даты - PullRequest
0 голосов
/ 10 января 2019

У меня есть следующее присоединение таблицы к самой последней записи для данного EMPLOYE_ID, и мне интересно, есть ли более эффективный / более быстрый способ получения самой последней записи, что будет лучшим способом?

SELECT * FROM EMPLOYEE
WHERE NOT EXISTS (
                       SELECT 1
                       FROM EMPLOYEE D
                       JOIN EMPLOYEE_HISTORY E
                               ON  E.EMPLOYEE_ID = D.EMPLOYEE_ID
                               AND E.CREATE_DATE IN (SELECT MAX(CREATE_DATE) 
                                                   FROM EMPLOYEE_HISTORY 
                                                   WHERE EMPLOYEE_ID = D.EMPLOYEE_ID)
                  )

Когда я сравнил план объяснения со следующим запросом, кажется, что приведенный ниже способ более затратен.

SELECT *
FROM EMPLOYEE
WHERE NOT EXISTS 
    (SELECT 1
       FROM EMPLOYEE D
       JOIN   (
            SELECT  E.*
            FROM EMPLOYEE_HISTORY E 
            INNER JOIN  (
                            SELECT  EMPLOYEE_ID
                                ,   MAX(CREATE_DATE) max_date
                            FROM EMPLOYEE_HISTORY E2 
                            GROUP BY EMPLOYEE_ID
                            ) EE
                            ON  EE.EMPLOYEE_ID = E.EMPLOYEE_ID
                            AND EE.max_date = E.CREATE_DATE
              ) A
       ON  A.EMPLOYEE_ID = D.EMPLOYEE_ID 
       AND ROWNUM = 1)

Значит, это действительно лучше?

Нет индекса CREATE_DATE, однако для PK указан EMPLOYEE_ID, CREATE_DATE

Ответы [ 3 ]

0 голосов
/ 10 января 2019

Я бы написал запрос, используя = вместо IN:

 SELECT 1
 FROM EMPLOYEE E JOIN
      EMPLOYEE_HISTORY EH
      ON EH.EMPLOYEE_ID = E.EMPLOYEE_ID AND
         EH.CREATE_DATE = (SELECT MAX(EH2.CREATE_DATE) 
                           FROM EMPLOYEE_HISTORY EH2
                           WHERE EH2.EMPLOYEE_ID = EH.EMPLOYEE_ID
                          );

IN является более общим, чем = для сравнения.

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

Если вы действительно хотите вернуть фактические столбцы, тогда я не уверен, есть ли способ сделать это быстрее.

Если вы действительно выбираете только 1, забудьте о самой последней записи и просто используйте EXISTS:

 SELECT 1
 FROM EMPLOYEE E
 WHERE EXISTS (SELECT 1
               FROM EMPLOYEE_HISTORY EH2
               WHERE EH2.EMPLOYEE_ID = E.EMPLOYEE_ID
              );

Единственным дополнительным условием, которое проверяет ваш запрос, является то, что CREATE_DATE не равен NULL, но я предполагаю, что это всегда так.

0 голосов
/ 10 января 2019

Используйте аналитическую функцию RANK (или DENSE_RANK или ROW_NUMBER):

SELECT 1
FROM EMPLOYEE E
JOIN   (
  SELECT *
  FROM   (
    SELECT  H.*,
            RANK() OVER ( PARTITION BY EMPLOYEE_ID ORDER BY CREATE_DATE DESC ) AS rnk
    FROM    EMPLOYEE_HISTORY H
  )
  WHERE rnk = 1
) H
ON  H.EMPLOYEE_ID = E.EMPLOYEE_ID
0 голосов
/ 10 января 2019

Если CREATE_DATE EMPLOYEE должен быть после максимального CREATE_DATE для этого EMPLOYEE_ID в EMPLOYEE_HISTORY?

Тогда для этого EMPLOYEE_ID не существует равного или большего CREATE_DATE в EMPLOYEE_HISTORY.

SELECT * 
FROM EMPLOYEE Emp
WHERE NOT EXISTS (
    SELECT 1
    FROM EMPLOYEE_HISTORY Hist
    WHERE Hist.EMPLOYEE_ID = Emp.EMPLOYEE_ID
      AND Hist.CREATE_DATE >= Emp.CREATE_DATE
)

Тест здесь

...