Oracle LEADING 提示——为啥需要这样做?
Posted
技术标签:
【中文标题】Oracle LEADING 提示——为啥需要这样做?【英文标题】:Oracle LEADING hint -- why is this required?Oracle LEADING 提示——为什么需要这样做? 【发布时间】:2010-02-23 21:04:30 【问题描述】:突然(但不幸的是,我不知道“突然”是什么时候;我知道它在过去的某个时候运行良好)我的一个查询开始需要 7 多秒而不是毫秒来执行。我有 1 个本地表和 3 个通过 DB 链接访问的表。 3 个远程表连接在一起,其中一个与我的本地表连接。
本地表的 where 子句只需要几毫秒即可自行执行,并且只返回几条(最多 10 或 100 条)记录。这 3 个远程表之间有数十万甚至数百万条记录,如果我适当地加入它们,我会得到数万或数十万条记录。
我只是加入远程表,以便我可以提取与本地表中每条记录相关的几条数据。
然而,似乎正在发生的事情是,Oracle 首先将远程表连接在一起,然后将我的本地表连接到最后的混乱中。这总是一个坏主意,尤其是考虑到现在存在的数据集,所以我在查询中添加了/*+ LEADING(local_tab remote_tab_1) */
提示,它现在以毫秒为单位返回。
我比较了解释计划,它们几乎相同,只是在其中一个远程表上只有一个 BUFFER SORT
。
我想知道什么可能导致 Oracle 以错误的方式处理这个问题?是索引问题吗?我应该寻找什么?
【问题讨论】:
您是否尝试过分析您的表格 (dbms_stats.gather_table_stats
)?
【参考方案1】:
在选择执行计划时,oracle 会估算不同计划的成本。该估计的一个关键信息是将从执行计划的一个步骤返回的行数。 Oracle 尝试使用“统计”来估计那些信息,即有关表包含多少行、列包含多少不同值的信息;这些值的分布有多均匀。
这些统计只是那个统计,可能是错误的,这也是oracle优化器误判的最重要原因之一。
因此,按照评论中的描述收集新的统计数据可能会有所帮助。查看该 dbms_stats 包的文档。调用该包的方式有很多种。
【讨论】:
【参考方案2】:我遇到的一个常见问题是连接许多表的查询,其中连接形成从一端到另一端的链,例如:
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 上的索引更具选择性)驱动查询。
表格上的统计数据可能会导致这两个计划之间的选择在刀刃上取得平衡;有一天它工作正常(从 tableA 驱动),第二天收集了新的统计数据,突然之间,从 tableE 驱动的替代计划成本更低并被选中。
在这种情况下,添加 LEADING 提示是一种将其推回到原始计划(即从 tableA 驱动)而不向优化器指示太多(即它不会强制优化器选择任何特定的连接方法)。
【讨论】:
【参考方案3】:您正在执行分布式查询优化,这是一个棘手的问题。可能是您的表的统计信息是最新的,但现在远程系统上的表不正常或已更改。或者远程系统添加/删除/修改了索引,这破坏了您的计划。 (这是考虑复制的绝佳理由——因此您可以控制索引和统计数据。)
也就是说,Oracle 对基数的估计是执行计划的主要驱动因素。 10053 跟踪分析(Jonathan Lewis 的基于成本的 Oracle Fundamentals 书中有从 8i 到 10.1 的精彩示例)可以帮助阐明您的语句现在被破坏的原因以及 LEADING
提示如何修复它。
DRIVING_SITE
提示可能是一个更好的选择,如果您知道您总是希望在访问远程站点之前先连接本地表;它阐明了您的意图,而无需像 LEADING
提示那样推动计划。
【讨论】:
【参考方案4】:可能不相关,但我曾经遇到过类似的情况,远程表已被单表视图替换。当它是一个表时,分布式查询优化器“看到”它有一个索引。当它变成一个视图时,它就再也看不到索引,也无法为在远程对象上使用索引的计划付出代价。
那是几年前的事了。我当时记录了我的分析here。
【讨论】:
【参考方案5】:RI,
不查看 SQL 就很难确定性能问题的原因。
当一个 Oracle 查询之前表现良好,突然开始表现不佳时,通常与以下两个问题之一有关:
A) 统计数据已过时。这是最简单、最快捷的检查方式,即使您有一个应该处理它的内务批处理流程……请务必仔细检查。
B) 数据量/数据模式变化。
在您的情况下,跨多个数据库运行分布式查询会使 Oracle 管理它们之间的性能的难度增加 10 倍。是否可以将这些表放在一个数据库中,或者将不同的架构所有者放在一个数据库中?
众所周知,提示很脆弱,因为 Oracle 没有义务遵循提示。当数据量或模式发生更多变化时,Oracle 可能会忽略提示并做它认为最好的事情(即最坏的;-)。
如果您不能将这些表全部放在一个数据库中,那么我建议您将查询分成两个语句:
-
在 sub-SELECT 上插入以将外部数据复制到当前数据库中的全局临时表中。
从全局临时表中选择以与您的其他表连接。
您无需借助提示即可完全控制上述第 1 步的执行情况。这种方法通常可以很好地扩展,让您花时间进行性能调整。我已经看到这种方法解决了许多复杂的性能问题。
Oracle 创建全新表或插入记录堆的开销比大多数人预期的要小得多。定义一个全局临时表可以进一步减少开销。
马修
【讨论】:
以上是关于Oracle LEADING 提示——为啥需要这样做?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 XPath previous-sibling::*[3] 有效,而leading-sibling::div[3] 无效?
ORACLE数据库设置date类型默认值后为啥还要手动添加?是否我写错了?