【问题标题】:Oracle 12c - Efficient way to join max date recordOracle 12c - 加入最大日期记录的有效方法
【发布时间】:2019-06-04 17:03:55
【问题描述】:

对于给定的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 上

【问题讨论】:

  • 你能显示完整的查询吗?
  • 那里不需要IN。子查询不会返回多于一行。可以使用=。 (但这很可能对性能没有影响。)
  • @VamsiPrabhala 请参阅编辑。
  • 取而代之的是IN,使用dense_rank解析函数过滤EMPLOYEE_HISTORY中的记录,然后(在更高级别)进行join。
  • 如果create_date 尚未在另一个索引中降序排列,您可以尝试在employee_history (employee_id ASC, create_date DESC) 上创建索引。

标签: sql oracle join oracle12c


【解决方案1】:

使用RANK(或DENSE_RANKROW_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

【讨论】:

  • 这是迄今为止成本最低的方法。 row_number 非常昂贵。谢谢!
【解决方案2】:

我会使用= 而不是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,但我猜这始终是正确的。

【讨论】:

    【解决方案3】:

    如果 EMPLOYEE 的 CREATE_DATE 必须在 EMPLOYEE_HISTORY 中该 EMPLOYEE_ID 的最大 CREATE_DATE 之后?

    那么对于那个 EMPLOYEE_ID,在 EMPLOYEE_HISTORY 中不存在相等或更高的 CREATE_DATE。

    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
    )
    

    测试here

    【讨论】:

      猜你喜欢
      • 2021-05-08
      • 2012-05-18
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      • 2019-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多