在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语句,但我没有任何运气。有什么方法可以进一步优化此查询?
有趣的提示: 当我们将Dell Toad用于我们的SQL IDE时,我在其上运行了一个内置的优化工具,并注意到其中一个查询将时间缩短了一半。但是,在对其进行检查时,所做的一切只是将此注释放入normal_cost计算中。如果没有任何优化建议,有人知道为什么这样做有效吗?当我删除它时,它会恢复其较慢的行为。
SELECT /*+ FULL(COST_REFERENCE) */
cost_1 + cost_2
FROM cost_reference
答案 0 :(得分:1)
使用正确的JOIN
语法编写查询。我还建议限定 all 列名,尤其是在使用相关子查询时。
您可以重写第二个子查询,以便它使用聚合。而且由于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)
答案 1 :(得分:1)
正如您所说的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进行完整检查。