首页 > 解决方案 > Oracle - 像文本宏一样使用 WITH 子句

问题描述

我有一个 SQL 查询,它在联合的两个不同位置重用一个复杂的子查询

SELECT A.PROJECT_ID, B.INFO B.MORE_INFO
FROM A
INNER JOIN (
     -- Complex subquery
) B ON A.PROJECT_ID = B.PROJECT_ID
WHERE -- Filter to a disjoint subset --

UNION

SELECT C.PROJECT_ID, B.INFO B.MORE_INFO
FROM C
INNER JOIN (
     --  SAME Complex subquery
) B ON C.PROJECT_ID = B.PROJECT_ID
WHERE -- Filter to a disjoint subset --

为了减少重复代码,我想使用 WITH 子句,所以我只需要编写一次复杂的子查询。

WITH B AS (
    -- Complex subquery
)

SELECT A.PROJECT_ID, B.INFO B.MORE_INFO
FROM A
INNER JOIN B ON A.PROJECT_ID = B.PROJECT_ID
WHERE -- Filter to a disjoint subset --

UNION

SELECT C.PROJECT_ID, B.INFO B.MORE_INFO
FROM C
INNER JOIN B ON A.PROJECT_ID = B.PROJECT_ID
WHERE -- Filter to a disjoint subset --

这可行,但现在查询需要 4 倍的时间来执行。查看这两个查询的解释计划,我想我知道发生了什么: WITH 子句正在创建一个没有索引的临时表,因此在连接 A 和 B 时,正在执行全表扫描。在原始查询的计划中,使用了下推谓词,从而减少了连接所需的工作。这与我发现的这篇现代 SQL 文章证实了这一点,该文章讨论了 WITH 子句如何对性能产生不利影响。

考虑到这一切,有没有一种方法可以让我使用 WITH 子句更像是 C 预处理器中的文本宏而不创建临时表?也许有一个我可以使用的计划提示?还是 Oracle 或 SQL 中可能有其他本机功能允许我做同样的事情?

最后,我希望看到 Oracle 执行与原始查询相同的计划,同时还利用 WITH 子句提供的代码模块化

一些注意事项:

标签: sqloracleindexingcommon-table-expression

解决方案


您可以尝试的最简单的方法是inline提示。

唉,由于某种我个人不明白的原因,这个提示没有记录(与它的对应部分相同,materialize提示),即使它们被广泛使用。根据您组织的规则,您可能会也可能无法使用此解决方案。我假设您知道提示,但不知道这个特定的提示;如果您需要更多帮助,请说出来。无论如何,您可能想在测试环境中尝试一下,看看可以做什么。

编辑(因为其他人也可能读到这个):

with子句应如下所示:

with
  b as ( select /*+ inline */ ...... complex query ....... )
.......

推荐阅读