我有一个查询从5个巨大的表中获取数据,请你帮我调整一下这个查询的性能:
SELECT DECODE(SIGN((t1.amount - NVL(t2.amount, 0)) - 4.999), 1, NVL(t2.amount, 0), t1.amount) AS amount_1,
t1.element_id,
t1.start_date ,
t1.amount,
NVL(t5.abrev, NULL) AS criteria,
t1.case_id ,
NVL(t5.value, NULL) segment,
add_months(t1.start_date, -1) invoice_date,
NVL((SELECT SUM(b.amount)
FROM TABLE1 a, TABLE3 b
WHERE a.element_id = b.element_id
AND b.date_invoicing < a.start_date
AND t1.element_id = a.element_id),
0) amount_2
FROM TABLE1 t1, TABLE2 t2, TABLE3 t3, TABLE4 t4, TABLE5 t5
WHERE t1.TYPE = 'INVOICE'
AND t2.case_id = t3.case_id
AND t2.invoicing_id = t3.invoicing_id
AND t2.date_unpaid IS NULL
AND t1.element_id = t3.element_id(+)
AND add_months(t1.start_date, -1) <
NVL(t4.DT_FIN_DT(+), SYSDATE)
AND add_months(t1.start_date, -1) >= t4.date_creation(+)
AND t1.case_id = t4.case_id(+)
AND t4.segment = t5.abrev(+)
AND t5.Type(+) = 'CRITERIA_TYPE';
有什么不对的,可以换成其他东西吗? 谢谢你的帮助
答案 0 :(得分:2)
您必须做的第一件事是使用显式连接。这会将您的联接与过滤器分开,并有助于您更好地调整它。
请检查这些连接是否正确。
SELECT
DECODE(SIGN((t1.amount - NVL(t2.amount, 0)) - 4.999), 1, NVL(t2.amount, 0), t1.amount) AS amount_1,
t1.element_id,
t1.start_date ,
t1.amount,
NVL(t5.abrev, NULL) AS criteria,
t1.case_id ,
NVL(t5.value, NULL) segment,
add_months(t1.start_date, -1) invoice_date,
NVL
(
(SELECT SUM(b.amount)
FROM TABLE1 a, TABLE3 b
WHERE a.element_id = b.element_id
AND b.date_invoicing < a.start_date
AND t1.element_id = a.element_id),
0) amount_2
FROM
TABLE1 t1
LEFT OUTER JOIN TABLE3 t3
on t1.element_id = t3.element_id
INNER JOIN TABLE2 t2,
on t2.invoicing_id = t3.invoicing_id
and t2.case_id = t3.case_id
LEFT OUTER JOIN TABLE4 t4
on t1.case_id = t4.case_id
LEFT OUTER JOIN TABLE5 t5
on t4.segment = t5.abrev
WHERE t1.TYPE = 'INVOICE'
AND t2.date_unpaid IS NULL
AND add_months(t1.start_date, -1) < NVL(t4.DT_FIN_DT(+), SYSDATE)
AND add_months(t1.start_date, -1) >= t4.date_creation(+)
AND t5.Type(+) = 'CRITERIA_TYPE';
如果是,那么你可以做几件事,但最好的办法是看执行计划。
答案 1 :(得分:1)
优化器可能已经产生了次优的执行计划。或者考虑到数据库实际需要做的工作量,它可能会尽可能快地运行。 如果没有解释计划,了解密钥,关系和索引就很难分辨出发生了什么。
当外部查询返回大量的行时,选择列表中的标量子查询通常不是一个好主意。
以下表达式可能会阻止优化程序因函数调用而使用统计信息。由于同样的原因,索引可能不会被使用。
AND add_months(t1.start_date, -1) < NVL(t4.DT_FIN_DT(+), SYSDATE)
AND add_months(t1.start_date, -1) >= t4.date_creation(+)
不能比那更具体:)
答案 2 :(得分:1)
您需要了解如何查看和理解执行计划。 This previous question是一个很好的起点。
答案 3 :(得分:1)
正如其他人所说,如果不看执行计划就很难说清楚。
但......我会关注的一些事情:
主要查询中对TABLE3的外部联接并不完整,正如@TonyAndrews在上面的评论中提到的那样。请参阅Common errors seen when using OUTER-JOIN上的“不完整加入路径”示例。 这意味着您的查询可能会产生错误的结果,但如果不知道查询和架构的完整意图,那么除了您之外,没有人可以确定这一点。
更新您的查询以使用Oracle风格INNER/[LEFT|RIGHT] OUTER
中的ANSI样式TableName.ColumnName(+)
语法将有助于使其更加明显。
标量子查询将为每一行运行并且可能很慢(假设TABLE3很大)。如果TABLE3.element_id
和TABLE3.date_invoicing
上没有有用的索引,那将会非常慢:
NVL((SELECT SUM(b.amount) FROM TABLE1 a, TABLE3 b WHERE a.element_id = b.element_id AND b.date_invoicing < a.start_date AND t1.element_id = a.element_id), 0) amount_2
因此,我没有看到需要在此子查询中再次包含TABLE1。将其重构为:
可能更好NVL((SELECT SUM(b.amount) FROM TABLE3 b WHERE t1.element_id = b.element_id AND b.date_invoicing < t1.start_date, 0) amount_2
或者,如果将b.amount
值相加的标准与包含SUM(b.amount) OVER (PARTITION BY b.element_id) amount_2
值相同的条件,您甚至可以更好地重构这个以使用分析函数(SO question,Oracle documentation)他们首先在查询中:
b.amount
显然,由于您在主查询和子查询中以不同方式加入TABLE3,因此您目前有不同的求和{{1}}标准,但我认为这更像是“不完整加入路径”的一个因素。通过有目的的设计(我猜测,因为我无法从代码本身告诉查询的意图)。
答案 4 :(得分:0)
当你将Select语句嵌套在另一个
中时,这是很奇怪的NVL((SELECT SUM(b.amount)
FROM TABLE1 a, TABLE3 b
WHERE a.element_id = b.element_id
AND b.date_invoicing < a.start_date
AND t1.element_id = a.element_id),
0) amount_2
你需要再次作为一个表写,然后在“From”之后加入。