我一直在努力提高这个查询的性能一段时间,在尝试了多种不同的方法后,我发现删除ANSI JOIN并使用传统语法可以根据解释计划显着降低成本(459928 vs. 82518117)。这是原始的(剪裁和修剪):
select distinct api.locn_id -- Explain Plan: 82518117
,i.item_set_id
,api.variant_id
from all_planogram_items api
join includes i
on api.variant_id = i.variant_id
or api.dept_id = i.dept_id
or api.category_id = i.category_id
or api.fixture_id = i.fixture_id
or api.aisle_id = i.aisle_id
where 1 = 1
and /* variant is not in excludes list*/
--e.item_set_id is null
not exists
... etc
以及传统联接的更好表现:
select distinct api.locn_id -- Explain Plan: 459928
,i.item_set_id
,api.variant_id
from all_planogram_items api, includes i
where 1 = 1
and (api.variant_id = i.variant_id
or api.dept_id = i.dept_id
or api.category_id = i.category_id
or api.fixture_id = i.fixture_id
or api.aisle_id = i.aisle_id)
and /* variant is not in excludes list*/
--e.item_set_id is null
not exists
... etc
就像我提到的,这个查询还有更多内容(内联视图等),但我所做的唯一更改就是在连接上。我觉得它与or
条款有关,但我自己无法解释。为什么这样效率更高?
更多信息:
以下是解释计划。我想重新讨论这些解释计划的唯一区别是上面解释的连接方法。奇怪的是,较低的成本和更快的传统JOIN解释计划是慢速ANSI JOIN解释计划的3倍(对于屏幕截图,解释计划太大,无法在此处发布文本版本):
传统的JOIN解释计划:
答案 0 :(得分:2)
为什么这样效率更高?
你的一个计划可能正在进行OR扩展,另一个可能不是。
Oracle转换ANSI连接语法查询的逻辑并不完美,与转换非ANSI连接语法查询的逻辑不完全相同。如果您将在Oracle的支持网站上查看补丁,您会发现几乎每个版本都有许多错误修正。
答案也延伸到其他领域。例如,在某些Oracle版本中,如果将其放入SELECT
语句或INSERT
语句中,则可以使用快速运行的CREATE TABLE AS SELECT
语句。
Oracle连接和ANSI连接在概念上是相同的,应该没有区别。但是,实际上存在差异。
答案 1 :(得分:0)
解释计划成本通常不是衡量绩效的好方法。对于类似的查询,它可能会有所不同,并且不会影响性能。您可能需要查看autotrace统计信息和tkprof以获得更多信息。另请参阅this link
答案 2 :(得分:0)
如果您使用SQL Developer或Toad(他们有一个直接向您显示执行计划的按钮),您可以轻松查看每个查询的解释计划。最好比较一下计划,看看,例如,由于复杂的ON条件,优化器没有“看到”将谓词从连接推送到组件表或视图的机会。将条件移动到WHERE子句允许优化器以不同的顺序(可能)查看过滤器并查看此类机会。这可能是完全错误的,但它通过查看解释计划显示了您可能会注意到的事情。