突然(但遗憾的是我不知道“突然”是什么时候;我知道它在过去的某个时刻运行得很好)我的一个查询开始需要 7 秒以上的时间而不是毫秒来执行。我有 1 个本地表和 3 个通过数据库链接访问的表。3 个远程表连接在一起,其中一个与我的本地表连接。

本地表的 where 子句本身只需要几毫秒执行,并且只返回少量(最多 10 或 100 条)记录。这 3 个远程表之间有数十万条、可能数百万条记录,如果我适当地连接它们,我会得到数万或数十万条记录。

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

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

我比较了解释计划,它们几乎相同,除了一个 BUFFER SORT 在其中一张远程桌子上。

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

有帮助吗?

解决方案

当选择执行计划,预言估计所述不同的计划的成本。对于估计一个关键信息是行的数量将得到执行计划的步骤返回。 Oracle尝试估计使用“统计”,即约信息那些表多少行含有多少不同值的列包含;这些值是如何均匀分布的。

这些统计数据只是统计,他们可能是错误的,这对于Oracle优化的判断失误的重要原因之一。

于是聚集在评论可能有助于说明新的统计数据。看看上dbms_stats包的文档。有许多不同的方式来调用包。

其他提示

一个常见的问题我已经遇到为连接许多表的查询,其中,所述连接从一端到另一端,e.g形成链:

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;

注意优化器可以如何选择开车从表A(例如,如果在ID0的索引是很好的选择性的)查询或从tableE(如果上tableE.ID5索引是更具选择性的)。

在表中的统计信息可能会导致上述两个图来平衡上的刀口之间的选择;有一天它的正常工作(从TableA的驱动),第二天新的统计信息收集和一下子的替代计划从tableE驱动具有较低的成本,并且选择

在这种情况下,添加前导提示是单程轻推回原计划(即,从表A驱动器),而不口述太多优化器(即,它不强制优化器选择任何特定的连接方法)。

您正在进行分布式查询优化,这是一个棘手的问题。您的表的统计信息可能是最新的,但现在远程系统上的表不正常或已更改。或者远程系统添加/删除/修改了索引,这破坏了您的计划。(这是考虑复制的一个很好的理由——这样您就可以控制它的索引和统计信息。)

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

DRIVING_SITE 如果您知道始终希望在连接远程站点之前先连接本地表,则提示可能是更好的选择;它澄清了你的意图,而不是像a那样推动计划 LEADING 暗示会。

可能并非相关,但我曾经在远程表已经被替换为单表视图类似的情况。当它是一个表中的分布式查询优化器“锯”,它有一个索引。当它成为一个视图它不能看到索引了,不能花费远程对象上使用的索引的俯视图。

这是一个几年前。我证明我的分析在当时这里

RI,

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

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

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

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

就您的情况而言,跨多个数据库运行分布式查询会使 Oracle 管理它们之间的性能的难度增加 10 倍。是否可以将这些表放在一个数据库中,或者将不同的模式所有者放在一个数据库中?

众所周知,提示非常脆弱,因为 Oracle 没有义务遵循提示。当数据量或模式发生更多变化时,Oracle 可能会忽略提示并执行它认为最好的操作(即最糟糕;-)。

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

  1. INSERT on sub-SELECT 将外部数据复制到当前数据库中的全局临时表。
  2. 从全局临时表中选择以与其他表连接。

您将完全控制上述步骤 1 的性能,而无需求助于提示。如果您花时间进行性能调整,这种方法通常可以很好地扩展。我已经看到这种方法解决了许多复杂的性能问题。

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

马修

scroll top