强制 Oracle 在远程数据库站点上处理递归 CTE(可能使用 DRIVING_SITE 提示)

Tom*_*ský 5 sql oracle database-link recursive-query oracle11g

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

对于其他“微小的本地,巨大的远程” -没有递归查询的情况,DRIVING_SITE提示效果很好。我还尝试将种子集从本地表导出到remotedb具有相同结构的辅助表中,并且 - 已登录remotedb- 作为纯本地查询(my_tableas pmy_table_seed_copyas i)运行查询。花了 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;
Run Code Online (Sandbox Code Playgroud)

在上面的查询中,我试过

  • 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 在两个内部选择中
  • (只是为了完整性 - 重写 toconnect by不适用于这种情况 - 实际上查询更复杂,并且使用不能由 表示的构造connect by

都没有成功(即 7 分钟后返回数据)。

Tom*_*ský 1

递归查询实际上执行广度优先搜索 - 种子行代表第 0 层,递归部分从(n-1)层上的元素中查找第 n层上的元素。原始查询旨在成为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;
Run Code Online (Sandbox Code Playgroud)

实际代码并不那么简单,因为DRIVING_SITE实际上并不直接使用,merge因此我们必须通过工作集合传输数据,但这是不同的故事。此外,插入的行数也不能轻易确定,必须将其计算为合并前后的行数之差。

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

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