什么时候使用WITH子句,它的主要好处是什么?

时间:2019-08-22 13:41:05

标签: 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;

5 个答案:

答案 0 :(得分:3)

  

有使用它的风险吗?

是的。 Oracle可能决定实现子查询,这意味着将其结果集写入磁盘,然后将其回读(除非这并不意味着在12cR2或更高版本中)。意外的I / O可能会降低性能。并非总是如此,通常我们可以相信优化器做出正确的选择。但是,Oracle为我们提供了一些提示,告诉优化器如何处理结果集:/*+ materialize */将其具体化,/*+ inline */将其保存在内存中。

我从潜在的不利之处开始,因为我认为了解WITH子句不是万灵丹很重要,它不会改善每个查询,甚至可能降低性能。例如,我对其他评论者的怀疑是,您发布的查询以任何方式都更快,因为您将其重新编写为公用表表达式。

通常,WITH子句的用例是:

  1. 我们想多次使用子查询的结果集

    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)
    
  2. 我们要构建一系列的子查询:

    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中实现复杂的业务逻辑很有用。但是,这可能会导致程序上的思维定势,并失去权力集结和连接。这也是一种风险。

  1. 我们要使用递归WITH子句。这使我们可以用更标准的方法替换Oracle自己的CONNECT BY语法。 Find out more

  2. 在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子句会带来一些好处:

  • 我认为查询的可读性更好
  • 您可以在主查询中多次使用同一子查询。您甚至可以层叠它们。
  • Oracle可以实现子查询,即Oracle可以创建一个临时表并在其中存储子查询的结果。这样可以提供更好的性能。

答案 2 :(得分:1)

WITH子句可以作为内联视图处理或解析为临时表。 SQL WITH子句与全局临时表的使用非常相似。该技术通常用于提高复杂子查询的查询速度,并使Oracle优化器将必要的谓词推送到视图中。

后者的优点是对子查询的重复引用可能更有效,因为可以轻松地从临时表中检索数据,而不是由每个引用重新查询。您应该根据具体情况评估WITH子句的性能含义。

您可以在此处了解更多信息:

http://www.dba-oracle.com/t_with_clause.htm

https://oracle-base.com/articles/misc/with-clause

答案 3 :(得分:1)

oracle中引入了

WITH子句以匹配SQL-99标准。

主要目的是减少复杂性和重复代码。

让我们说,您需要找到一个部门的平均薪水,然后获取所有高于该部门平均薪水(d1)的部门(d1)。

这可以使对子查询的多个引用更加有效和可读。

MATERIALIZEINLINE优化器提示可用于影响决策。未记录的MATERIALIZE提示告诉优化器将子查询解析为全局临时表,而INLINE提示告诉优化器内联处理查询。使用提示的决定完全取决于我们将在查询中实现的逻辑。

在oracle 12c中,引入了WITH子句中的PL / SQL Block声明。

您必须从oracle文档中引用它。

干杯!

答案 4 :(得分:0)

要考虑的一点是,不同的RDBMS处理with子句-aka公用表表达式(CTE)aka子查询分解-不同:

因此,根据您使用的RDBMS及其版本,您的里程可能会有所不同。