【问题标题】:force Oracle to process recursive CTE on remote db site (perhaps using DRIVING_SITE hint)强制 Oracle 在远程数据库站点上处理递归 CTE(可能使用 DRIVING_SITE 提示)
【发布时间】:2021-06-05 02:15:49
【问题描述】:

我正在尝试从远程表中获取数据。使用递归 CTE 从本地表中的种子数据集扩展数据。查询非常慢(300 行种子到 800 最终行需要 7 分钟)。

对于其他没有递归查询的"tiny local, huge remote"-case,DRIVING_SITE 提示效果很好。我还尝试将种子集从本地表导出到具有相同结构的remotedb 上的辅助表中 - 登录remotedb - 作为纯本地查询运行查询(my_table 作为pmy_table_seed_copy 作为@987654328 @)。花了 4 秒,这让我相信强制查询到远程站点会加快查询速度。

强制Oracle在远程站点执行递归查询的正确方法是什么?

with s (id, data) as (
  select p.id, p.data
  from my_table@remotedb p
  where p.id in (select i.id from my_table i)
  union all
  select p.id, p.data
  from s
  join my_table@remotedb p on ...
)
select /*+DRIVING_SITE(p)*/ s.*
from s;

在上面的查询中,我试过了

  • select /*+DRIVING_SITE(p)*/ s.* 在主选择中
  • select /*+DRIVING_SITE(s)*/ s.* 在主选择中
  • 在整个查询中省略 DRIVING_SITE
  • select /*+DRIVING_SITE(x)*/ s.* from s, dual@remotedb x 作为主选
  • select /*+DRIVING_SITE(p)*/ p.id, p.data 在第一个内部选择中
  • select /*+DRIVING_SITE(p)*/ p.id, p.data 在两个内部选择中
  • select /*+DRIVING_SITE(p) MATERIALIZE*/ p.id, p.data 在两个内部选择中
  • (仅出于完整性考虑 - 重写为 connect by 不适用于这种情况 - 实际上查询更复杂,并且使用了 connect by 无法表达的结构)

均未成功(即 7 分钟后返回数据)。

【问题讨论】:

  • 在您发布的查询中,p 不在提示范围内。如果你把这个提示放在CTE 里面 - 可能在两个分支中会有什么不同吗?或者,也许,再加上实现 CTE 的提示? (只是推测......没有真正的洞察力,也无法测试。)
  • @AlexPoole 谢谢,你的建议很有趣,我没有想到。不幸的是,两者都不起作用。我将通过这些尝试更新问题。
  • 尝试使用 cte 在远程数据库创建视图,
  • @gsalem 谢谢,目前我不清楚如何将种子集合并到视图中。 CTE 的锚点部分应该以某种方式反映种子集,否则整个表将成为种子集。参数化视图在这种情况下会有所帮助,但 Oracle 不支持它。我目前正在尝试实现远程流水线功能。
  • 您的远程表是否很大,而您在递归中消耗的很少?也许最好将数据拉到本地并进行递归?

标签: sql oracle oracle11g recursive-query database-link


【解决方案1】:

递归查询实际上执行广度优先搜索 - 种子行表示第 0 层,递归部分从 (n-1)上的元素中找到第 n 层的元素>-th 级别。原始查询旨在成为merge ... using ... 子句的一部分。

因此我将查询重写为 PLSQL 循环。每个循环生成一个级别。合并可防止插入重复项,因此最终不会添加新行并退出循环(构造传递闭包)。伪代码:

loop
  merge into my_table using (
    select /*+DRIVING_SITE(r)*/ distinct r.* /*###BULKCOLLECT###*/
    from my_table          l
    join my_table@remotedb r on ...  -- same condition as s and p in original question are joined on
  ) ...
  exit when rows_inserted = 0;
end loop;

实际代码并不那么简单,因为DRIVING_SITE 实际上并不能直接与merge 一起工作,所以我们必须通过工作集合传输数据,但那是different story。此外,插入的行数也不容易确定,它必须计算为合并前后的行数之差。

解决方案并不理想。无论如何,它比递归 CTE(30 秒,13 个周期)快得多,因为可证明查询使用了 DRIVING_SITE 提示。

如果有人找到答案如何使递归查询正常工作或证明它是不可能的,我会将问题留待一段时间等待。

【讨论】:

    猜你喜欢
    • 2014-09-27
    • 1970-01-01
    • 1970-01-01
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多