Oracle LEADING提示 - 为什么需要这样做?

时间:2010-02-23 21:04:31

标签: sql oracle query-hints

突然(但不幸的是我不知道“突然”是什么时候;我知道它在过去的某个时刻运行正常)我的一个查询开始花费7秒多而不是毫秒来执行。我有一个本地表和3个表通过数据库链接访问。 3个远程表连接在一起,其中一个与我的本地表连接。

本地表的where子句只需要几毫安就可以自行执行,并且只返回一些(最多10个或100个)记录。 3个远程表之间有数十万甚至数百万条记录,如果我加入它们,我会得到数十或数十万条记录。

我只加入远程表,以便我可以提取与本地表中每条记录相关的一些数据。

然而,似乎正在发生的事情是Oracle首先将远程表连接在一起,然后将本地表连接到最后的那个混乱。这总是一个坏主意,特别是考虑到现在存在的数据集,所以我在查询中添加了/*+ LEADING(local_tab remote_tab_1) */提示,它现在以毫秒为单位返回。

我比较了解释计划,它们几乎完全相同,除了其中一个远程表上的单个BUFFER SORT

我想知道什么可能导致Oracle以错误的方式处理这个问题?这是指数问题吗?我应该寻找什么?

5 个答案:

答案 0 :(得分:5)

在选择执行计划时,oracle会估算不同计划的成本。该估计的一个关键信息是从执行计划的步骤返回的行数。 Oracle尝试使用“统计”来估计那些,即有关表包含多少行的信息,列包含多少个不同的值;这些值分布的均匀程度。

这些统计数据只是统计数据,而且可能是错误的,这是对oracle优化器误判的最重要原因之一。

因此,收集评论中描述的新统计信息可能会有所帮助。查看有关该dbms_stats包的文档。调用该软件包的方法有很多种。

答案 1 :(得分:3)

我遇到的一个常见问题是连接许多表的查询,其中连接形成从一端到另一端的链,例如:

SELECT *
FROM   tableA, tableB, tableC, tableD, tableE
WHERE  tableA.ID0 = :bind1
AND    tableA.ID1 = tableB.ID1
AND    tableB.ID2 = tableC.ID2
AND    tableC.ID3 = tableD.ID3
AND    tableD.ID4 = tableE.ID4
AND    tableE.ID5 = :bind2;

注意优化器如何选择从tableA驱动查询(例如,如果ID0上的索引具有良好的选择性)或者从tableE驱动查询(如果tableE.ID5上的索引更具选择性)。

表格的统计数据可能会导致这两个计划之间的选择在刀刃上达到平衡;有一天它工作正常(从桌子A开车),第二天收集了新的统计数据,突然之间从tableE开始的替代计划成本更低并且被选中。

在这种情况下,添加LEADING提示是单向将其推回到原始计划(即来自tableA的驱动器),而不会向优化器指示太多(即它不强制优化器选择任何特定的连接方法。)

答案 2 :(得分:2)

你正在进行分布式查询优化,这是一个棘手的野兽。可能是您的表的统计信息是最新的,但现在远程系统中的表已经不完整或已更改。或者远程系统添加/删除/修改了索引,这破坏了您的计划。 (这是考虑复制的一个很好的理由 - 因此您可以控制索引和统计数据。)

也就是说,Oracle对基数的估计是执行计划的主要驱动因素。 10053跟踪分析(Jonathan Lewis的“基于成本的Oracle基础知识”一书中有8i到10.1的精彩示例)可以帮助阐明为什么语句现在被破坏以及LEADING提示如何修复它。

如果您知道在追踪远程站点之前总是希望首先连接本地表,那么DRIVING_SITE提示可能是更好的选择;它以LEADING提示的方式明确了你的意图而没有推动计划。

答案 3 :(得分:1)

可能不相关,但是一旦远程表被单表视图替换,我就有类似的情况。当它是一个表时,分布式查询优化器“看到”它有一个索引。当它成为一个视图时,它再也看不到索引,并且不能花费在远程对象上使用索引的计划。

那是几年前的事。我在here时记录了我的分析。

答案 4 :(得分:1)

RI,

如果没有看到SQL,很难确定性能问题的原因。

当Oracle查询之前表现良好并突然开始表现不佳时,通常与以下两个问题之一有关:

  

A)统计数据已过期。这是检查的最简单,最快捷的方法,即使您有一个应该处理它的内务处理批处理...总是仔细检查。

     

B)数据量/数据模式的变化。

在您的情况下,跨多个数据库运行分布式查询会使Oracle难以管理它们之间的性能。是否可以将这些表放在一个数据库中,可能是一个数据库中的独立架构所有者?

提示是众所周知的脆弱,因为甲骨文没有义务遵循这一提示。当数据量或模式发生更改时,Oracle可能会忽略该提示并执行它认为最好的操作(即最差; - )。

如果您不能将这些表全部放在一个数据库中,那么我建议您将查询分为两个语句:

  1. INSERT on sub-SELECT将外部数据复制到当前数据库中的全局临时表。
  2. 从全局临时表中选择要与其他表联接。
  3. 您无需借助提示即可完全控制上述第1步的效果。这种方法通常可以很好地扩展,为您提供时间来进行性能调整。我已经看到这种方法解决了许多复杂的性能问题。

    Oracle创建整个新表或插入一堆记录的开销比大多数人预期的要小得多。定义全局临时表可以进一步减少开销。

    马修