强制 Oracle 在远程数据库站点上处理递归 CTE(可能使用 DRIVING_SITE 提示)
force Oracle to process recursive CTE on remote db site (perhaps using DRIVING_SITE hint)
我正在尝试从远程 table 获取数据。使用递归 CTE 从本地 table 中的种子数据集扩展数据。查询非常慢(300 行种子行到 800 行最终行需要 7 分钟)。
对于其他 "tiny local, huge remote" 没有递归查询的情况,DRIVING_SITE
提示非常有效。我还尝试将种子集从本地 table 导出到具有相同结构的 remotedb
上的辅助 table 并且 - 作为纯本地登录 remotedb
- 运行 查询查询(my_table
作为 p
,my_table_seed_copy
作为 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;
在上面的查询中,我尝试了
select /*+DRIVING_SITE(p)*/ s.*
主要 select
select /*+DRIVING_SITE(s)*/ s.*
主要 select
- 在整个查询中省略
DRIVING_SITE
select /*+DRIVING_SITE(x)*/ s.* from s, dual@remotedb x
作为主要 select
select /*+DRIVING_SITE(p)*/ p.id, p.data
在第一个内部 select
select /*+DRIVING_SITE(p)*/ p.id, p.data
在两个内部 selects
select /*+DRIVING_SITE(p) MATERIALIZE*/ p.id, p.data
在两个内部 selects
- (只是为了完整性 - 重写为
connect by
不适用于这种情况 - 实际上查询更复杂并且使用无法用 connect by
表达的构造)
全部失败(即 7 分钟后返回数据)。
递归查询实际上执行广度优先搜索 - 种子行表示第 0 级,递归部分从 上的元素中找到第 n 级上的元素( n-1)-第级。原始查询旨在成为 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
提示。
如果有人找到如何使递归查询工作或证明它不可能的答案,我会将问题悬而未决一段时间。
我正在尝试从远程 table 获取数据。使用递归 CTE 从本地 table 中的种子数据集扩展数据。查询非常慢(300 行种子行到 800 行最终行需要 7 分钟)。
对于其他 "tiny local, huge remote" 没有递归查询的情况,DRIVING_SITE
提示非常有效。我还尝试将种子集从本地 table 导出到具有相同结构的 remotedb
上的辅助 table 并且 - 作为纯本地登录 remotedb
- 运行 查询查询(my_table
作为 p
,my_table_seed_copy
作为 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;
在上面的查询中,我尝试了
select /*+DRIVING_SITE(p)*/ s.*
主要 selectselect /*+DRIVING_SITE(s)*/ s.*
主要 select- 在整个查询中省略
DRIVING_SITE
select /*+DRIVING_SITE(x)*/ s.* from s, dual@remotedb x
作为主要 selectselect /*+DRIVING_SITE(p)*/ p.id, p.data
在第一个内部 selectselect /*+DRIVING_SITE(p)*/ p.id, p.data
在两个内部 selectsselect /*+DRIVING_SITE(p) MATERIALIZE*/ p.id, p.data
在两个内部 selects- (只是为了完整性 - 重写为
connect by
不适用于这种情况 - 实际上查询更复杂并且使用无法用connect by
表达的构造)
全部失败(即 7 分钟后返回数据)。
递归查询实际上执行广度优先搜索 - 种子行表示第 0 级,递归部分从 上的元素中找到第 n 级上的元素( n-1)-第级。原始查询旨在成为 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
提示。
如果有人找到如何使递归查询工作或证明它不可能的答案,我会将问题悬而未决一段时间。