优化Oracle中的聚合函数

时间:2013-07-12 16:14:54

标签: sql oracle aggregate-functions

我有一个关于提取客户信息的查询,我正在添加max()函数来查找最近的订单日期。如果没有聚合,查询需要0.22秒才能运行,但使用它需要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:根据要求,以下是我在此问题中引用的查询计划。

With Aggregate

Without Aggregate

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分: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');

尝试查询。