eld*_*inT 3 oracle query-optimization common-table-expression database-performance
我正在处理有关优化查询的任务。改进方法之一是使用 WITH 子句。我注意到它做得很好,并且缩短了执行时间,但我现在不确定,我什么时候应该使用 WITH 子句,使用它是否有任何风险?
这是我正在处理的查询之一:
WITH MY_TABLE AS
( SELECT PROD_KY,
sum(GROUPISPRIVATE) AS ISPRIVATE,
sum(GROUPISSHARED) AS ISSHARED
FROM
(
SELECT GRP_PROD_CUSTOMER.PROD_KY,
1 as ISPRIVATE,
0 as ISSHARED
FROM CUSTOMER
JOIN GRP_CUSTOMER ON GRP_CUSTOMER.CUST_KY = CUSTOMER.CUST_KY
JOIN GRP_PROD_CUSTOMER ON GRP_PROD_CUSTOMER.GRP_KY = GRP_CUSTOMER.GRP_KY
GROUP BY GRP_PROD_CUSTOMER.PROD_KY
)
GROUP BY PROD_KY
)
SELECT * FROM MY_TABLE;
Run Code Online (Sandbox Code Playgroud)
使用它有任何风险吗?
是的。Oracle 可能决定具体化子查询,这意味着将其结果集写入磁盘然后读回(除非在 12cR2 或更高版本中可能不是这样)。意外的 I/O 可能会影响性能。并非总是如此,通常我们可以相信优化器会做出正确的选择。但是,Oracle 已经为我们提供了一些提示,告诉优化器如何处理结果集:/*+ materialize */
嗯,/*+ inline */
将它具体化并将其保存在内存中。
我从这个潜在的缺点开始,因为我认为理解 WITH 子句不是灵丹妙药很重要,它不会改善每个查询,甚至可能会降低性能。例如,我同意其他评论者的怀疑,即您发布的查询在任何方面都更快,因为您将其重新编写为公共表表达式。
通常,WITH 子句的用例是:
我们想多次使用子查询的结果集
with cte as
( select blah from meh )
select *
from t1
join t2 on t1.id = t2.id
where t1.col1 in ( select blah from cte )
and t2.col2 not in ( select blah from cte)
Run Code Online (Sandbox Code Playgroud)我们想要构建一个级联的子查询:
with cte as
( select id, blah from meh )
, cte2 as
( select t2.*, cte.blah
from cte
join t2 on t2.id = cte.id)
, cte3 as
( select t3.*, cte2.*
from cte2
join t3 on t3.col2 = cte2.something )
….
Run Code Online (Sandbox Code Playgroud)第二种方法很吸引人,可用于在纯 SQL 中实现复杂的业务逻辑。但它可能会导致程序思维方式并失去权力集和连接。这也是一种风险。
我们想使用递归 WITH 子句。这允许我们用更标准的方法替换 Oracle 自己的 CONNECT BY 语法。了解更多
在 12c 及更高版本中,我们可以在 WITH 子句中编写用户定义的函数。这是一个强大的功能,特别是对于需要在 PL/SQL 中实现一些逻辑但对数据库只有 SELECT 访问权限的用户。了解更多
作为记录,我已经看到了第二种类型 WITH 子句的一些非常成功和高性能的使用。然而,我也看到过 WITH 的使用,因为它本来可以很容易地编写一个内联视图。例如,这只是使用 WITH 子句作为语法糖......
with cte as
( select id, blah from meh )
select t2.*, cte.blah
from t2
join cte on cte.id = t2.id
Run Code Online (Sandbox Code Playgroud)
......并且会更清楚......
select t2.*, cte.blah
from t2
join ( select id, blah from meh ) cte on cte.id = t2.id
Run Code Online (Sandbox Code Playgroud)