我有一个关于提取客户信息的查询,我正在添加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:根据要求,以下是我在此问题中引用的查询计划。
答案 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');
尝试查询。