我在Oracle查询中遇到了一些性能问题,所以我下载了Quest SQL Optimizer for Oracle的试用版,它进行了一些更改,大大提高了查询的性能。我不确定为什么推荐的查询有这样的改进;任何人都可以提供解释吗?
之前:
SELECT t1.version_id,
t1.id,
t2.field1,
t3.person_id,
t2.id
FROM table1 t1,
table2 t2,
table3 t3
WHERE t1.id = t2.id
AND t1.version_id = t2.version_id
AND t2.id = 123
AND t1.version_id = t3.version_id
AND t1.VERSION_NAME <> 'AA'
order by t1.id
后:
SELECT /*+ USE_NL_WITH_INDEX(t1) */ t1.version_id,
t1.id,
t2.field1,
t3.person_id,
t2.id
FROM table2 t2,
table3 t3,
table1 t1
WHERE t1.id = t2.id + 0
AND t1.version_id = t2.version_id + 0
AND t2.id = 123
AND t1.version_id = t3.version_id + 0
AND t1.VERSION_NAME || '' <> 'AA'
AND t3.version_id = t2.version_id + 0
order by t1.id
问题:
为什么重新排列FROM
子句中表格的顺序有帮助?
为什么在+ 0
子句比较中添加WHERE
有帮助?
为什么|| '' <> 'AA'
子句WHERE
比较中的VERSION_NAME
有帮助?这是处理此列上可能nulls
的更有效方法吗?
答案 0 :(得分:2)
如果您通过解释计划运行这两个陈述,您将自己看到差异。为此,请发出:
explain plan
for
<your query>;
select * from table(dbms_xplan.display);
如果仍然不清楚为什么会出现这种差异,那么请在此处粘贴输出。
此致 罗布。
PS:“+ 0”和“||”'只是一些技巧,可以确保不使用列上的常规索引。它们也使您的查询不太可读,所以我会自己调整它们,而不是依赖于工具。
答案 1 :(得分:2)
首先要注意的是,“后”计划的成本低于“之前”计划。
这告诉我们第一个查询没有考虑为第二个查询选择的计划,因为Oracle会选择较低的成本计划。
添加USE_NL_WITH_INDEX提示不会影响任何计划的成本。它的作用是,如果一个带有索引计划的嵌套循环可用,那么即使Oracle是更有效的计划,任何其他计划也将被排除在考虑之外。
其次,“t1.id = t2.id”的谓词允许我们从t1开始并链接到t2或从t2开始并链接到t1。将该谓词更改为“t1.id = t2.id + 0”意味着它只能从t2(将0添加到id)链接到t1。 Oracle不够明白,它可以从t1开始(从id减去0)并加入到t2(或者添加/最小化0无关紧要)。
这些技巧都会阻止使用特定的访问路径。两者都不能说明所选计划的成本明显下降。
同时给出“AND t1.version_id = t2.version_id”和“AND t1.version_id = t3.version_id”,然后 “t3.version_id = t2.version_id”是给定的(受数据类型转换的影响)。但是,明确地添加它会向Oracle建议,由于正在应用额外条件,因此将返回更少的行,这可能会以更低的成本反映出来。
如果t2和t3 version_id不是数字,则可以解释成本的变化。 “+ 0”将强制进行数据类型转换,这可能允许使用索引。我认为这不太可能。
我怀疑原计划是从t1开始的(t1.id = 123和version_name&lt;&gt;'AA')。额外的谓词会(可能)迫使它从t2开始。
个人而言,我不喜欢任何其他优化。没有解决为什么最初选择了错误的计划。答案 2 :(得分:1)
我同意彼得的评论 - 尝试从“改进的”查询中提取并查看它是否仍然表现良好。
如果oracle不想使用它,您可能需要更新此表的统计信息...
编辑:每个表中的version_id和id列是否都是相同的数据类型?
答案 3 :(得分:1)
补充问题汤姆提交的答案here is a link使用工具进行调整(或其他n步骤方法)。
答案 4 :(得分:0)
几乎可以肯定,这些表的统计数据是错误的,导致优化器选择一个糟糕的计划。
收集表和索引的统计信息(如果您无法控制此类事件,请将DBA收到),然后再次尝试查询。