[英]Optimize Oracle SQL Select with multiple MAX subqueries
在 Oracle 12c 数据库中,我有以下查询:
SELECT pd.product_id,
sd.column_1,
sd.column_2,
(SELECT ROUND ( SUM (cost_1 + cost_2) / MAX (ref_coefficient), 4)
FROM cost_reference
WHERE product_name = sd.product_name)
AS weighted_cost,
(SELECT cost_1 + cost_2
FROM cost_reference
WHERE product_name = sd.product_name
AND ref_coefficient = (SELECT MAX (ref_coefficient)
FROM cost_reference
WHERE product_name = sd.product_name ))
AS normal_cost
FROM sales_data sd, product_data pd
WHERE sd.product_name = pd.product_name
AND sd.date = SYSDATE
cost_reference 表用于根据当前加载的内容拉取某个系数。 weighted_cost 和 normal_cost 列是根据显示的子查询计算的。 然而,多次调用 MAX(ref_coefficient) 确实减慢了这个查询的速度。 整个过程大约需要 3 秒,但我们想尝试缩短该时间,因为这在数据不断刷新的地方被调用,最终结果只有大约 50 行。 Cost_reference 通常包含大约 2500 行。
适当的索引也在那里,因为当它们不存在时,大约需要 10 秒。 如果我取出这些计算列,查询是即时的。 我曾尝试加入 cost_reference 表或使用 WITH 语句,但我没有任何运气。 有没有办法进一步优化这个查询?
有趣的提示:由于我们的 SQL IDE 有 Dell Toad,我在其上运行了一个内置的优化工具,并注意到其中一个查询将时间缩短了一半。 然而,在检查它时,它所做的只是将此注释放入 normal_cost 计算中。 如果没有任何优化建议,有谁知道为什么会这样? 当我删除它时,它会恢复到较慢的行为。
SELECT /*+ FULL(COST_REFERENCE) */
cost_1 + cost_2
FROM cost_reference
使用正确的JOIN
语法编写查询。 我还建议限定所有列名,尤其是在使用相关子查询时。
您可以重写第二个子查询,使其使用聚合。 并且因为sysdate
具有时间组件,所以您的WHERE
子句不太可能符合您的预期。
因此,我将查询重写为:
SELECT pd.product_id, sd.column_1, sd.column_2,
(SELECT ROUND(SUM(cost_1 + cost_2) / MAX(ref_coefficient), 4)
FROM cost_reference cr
WHERE cr.product_name = sd.product_name
) AS weighted_cost,
(SELECT MAX(cr.cost_1 + cr.cost_2) KEEP (DENSE_RANK FIRST ORDER BY ref_coefficient DESC)
FROM cost_reference cr
WHERE cr.product_name = sd.product_name
) AS normal_cost
FROM sales_data sd JOIN
product_data pd
ON sd.product_name = pd.product_name
WHERE sd.date = TRUNC(SYSDATE)
对于此查询,您需要以下索引:
sales_data(date, product_name)
product_data(product_name)
cost_reference(product_name, ref_coefficient, cost_1, cost_2)
正如你所说的 cost_reference 有 2.5k 行,那么你可以试试这个(
SELECT pd.product_id, sd.column_1, sd.column_2,
weighted_cost,
normal_cost
FROM sales_data sd JOIN
product_data pd
ON sd.product_name = pd.product_name
join (select product_name, ROUND(SUM(cost_1 + cost_2) / MAX(ref_coefficient), 4) weighted_cost,
MAX(cr.cost_1 + cr.cost_2) KEEP (DENSE_RANK FIRST ORDER BY ref_coefficient DESC) normal_cost
from cost_reference cr
group by product_name) cr on (cr.product_name=sd.product_name)
WHERE sd.date = TRUNC(SYSDATE)
这个想法是只有一个 cost_reference 聚合,因为它很小,结果集也很小。 注意:没有用这些表完整检查 sql。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.