我正在从事有关优化查询的任务。改进方法之一是使用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;
答案 0 :(得分:3)
有使用它的风险吗?
是的。 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)
我们要构建一系列的子查询:
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 )
….
第二种方法令人迷惑,对于在纯SQL中实现复杂的业务逻辑很有用。但是,这可能会导致程序上的思维定势,并失去权力集结和连接。这也是一种风险。
我们要使用递归WITH子句。这使我们可以用更标准的方法替换Oracle自己的CONNECT BY语法。 Find out more
在12c及更高版本中,我们可以在WITH子句中编写用户定义的函数。这是一项强大的功能,特别是对于需要在PL / SQL中实现某些逻辑但仅具有对数据库的SELECT访问权限的用户而言。 Find out more
为记录起见,我看到了第二种WITH子句的一些非常成功和高性能的用法。但是,当编写内联视图同样容易时,我也看到了WITH的用法。例如,这只是使用WITH子句作为语法糖...
with cte as
( select id, blah from meh )
select t2.*, cte.blah
from t2
join cte on cte.id = t2.id
...并且会更清晰地显示为...
select t2.*, cte.blah
from t2
join ( select id, blah from meh ) cte on cte.id = t2.id
答案 1 :(得分:1)
就WITH
语句(又名通用表表达式,CTE)而言,您的查询是毫无用处的
无论如何,使用WITH
子句会带来一些好处:
答案 2 :(得分:1)
WITH子句可以作为内联视图处理或解析为临时表。 SQL WITH子句与全局临时表的使用非常相似。该技术通常用于提高复杂子查询的查询速度,并使Oracle优化器将必要的谓词推送到视图中。
后者的优点是对子查询的重复引用可能更有效,因为可以轻松地从临时表中检索数据,而不是由每个引用重新查询。您应该根据具体情况评估WITH子句的性能含义。
您可以在此处了解更多信息:
答案 3 :(得分:1)
WITH
子句以匹配SQL-99标准。
主要目的是减少复杂性和重复代码。
让我们说,您需要找到一个部门的平均薪水,然后获取所有高于该部门平均薪水(d1)的部门(d1)。
这可以使对子查询的多个引用更加有效和可读。
MATERIALIZE
和INLINE
优化器提示可用于影响决策。未记录的MATERIALIZE提示告诉优化器将子查询解析为全局临时表,而INLINE
提示告诉优化器内联处理查询。使用提示的决定完全取决于我们将在查询中实现的逻辑。
在oracle 12c中,引入了WITH
子句中的PL / SQL Block声明。
您必须从oracle文档中引用它。
干杯!
答案 4 :(得分:0)
要考虑的一点是,不同的RDBMS处理with子句-aka公用表表达式(CTE)aka子查询分解-不同:
因此,根据您使用的RDBMS及其版本,您的里程可能会有所不同。