1

我有一个提取客户信息的查询,我正在添加一个max()函数来查找最近的订单日期。如果没有聚合,查询需要 0.23 秒才能运行,但使用它需要 12.75 秒。

这是查询:

SELECT U.SEQ, MAX(O.ORDER_DATE) FROM CUST_MST U
INNER JOIN ORD_MST O ON U.SEQ = O.CUST_NUM
WHERE U.SEQ = :customerNumber
GROUP BY U.SEQ;

ORD_MST是一个包含 890,000 条记录的表。

有没有更有效的方法来获得这个功能?

编辑:为了记录,没有什么特别阻止我运行两个查询并将它们加入我的程序中。我觉得非常奇怪的是,这样一个简单的查询需要这么长时间才能运行。在这种情况下,让数据库进行信息连接会更干净/更容易,但这不是我完成它的唯一方法。

编辑 2:根据要求,这里是我在这个问题中引用的查询的计划。

带骨料

无骨料

4

2 回答 2

2

您的查询的问题是您完全连接两个表,然后针对整个结果执行 max 函数,最后 where 语句过滤您的行。

您已经改进了连接,只需连接具有特定 custid 的行而不是完整的表,应该如下所示:

SELECT U.SEQ, MAX(O.ORDER_DATE) FROM 
  (SELECT * FROM CUST_MST WHERE SEQ = :customerNumber )  U
INNER JOIN 
  (SELECT * FROM ORD_MST WHERE CUST_NUM = :customerNumber) O ON U.SEQ = O.CUST_NUM
GROUP BY U.SEQ;

另一种选择是使用 order by 并过滤第一个 rownum。它不是干净的方式。可能会更快,如果不是,您还需要一个子选择来不订购完整的表格。有一段时间没有使用 oracle,但它应该看起来像这样:

SELECT * FROM
(
 SELECT U.SEQ, O.ORDER_DATE FROM CUST_MST U
 INNER JOIN ORD_MST O ON U.SEQ = O.CUST_NUM
 WHERE U.SEQ = :customerNumber
 GROUP BY U.SEQ;
 ORDER BY O.ORDER_DATE DESC
)
WHERE ROWNUM = 1

您是否出于某种原因被迫使用联接,或者为什么不直接从 ORD_MST 中选择而不使用联接?

编辑 还有一个想法:

SELECT * FROM 
(SELECT CUST_NUM, MAX(ORDER_DATE) FROM ORD_MST WHERE CUST_NUM = :customerNumber GROUP BY CUST_NUM) O
INNER JOIN CUST_MST U ON O.CUST_NUM = U.SEQ

如果内部选择只需要一秒钟,那么连接应该立即生效。

于 2013-07-12T16:54:41.530 回答
2

运行以下命令:

Explain plan for 
SELECT U.SEQ, MAX(O.ORDER_DATE) FROM CUST_MST U
INNER JOIN ORD_MST O ON U.SEQ = O.CUST_NUM
WHERE U.SEQ = :customerNumber
GROUP BY U.SEQ;

select * from table( dbms_xplan.display );

并在此处发布结果。在不知道执行计划的情况下,我们只能猜测真正发生了什么。

顺便提一句。我的感觉是为 ORD_MST 表添加包含 cust_num+order_date 列的复合索引可以解决问题(假设 SEQ 是 CUST_MST 表的主键并且它已经具有唯一索引)。尝试:

CREATE INDEX idx_name ON ORD_MST( cust_num, order_date );

此外,在使用命令创建索引刷新统计信息后:

 EXEC DBMS_STATS.gather_table_stats('your-schema-name', 'CUST_MST');
 EXEC DBMS_STATS.gather_table_stats('your-schema-name', 'ORD_MST');

试试你的查询。

于 2013-07-12T18:29:28.657 回答