用子句执行

时间:2016-07-28 09:21:56

标签: oracle sybase teradata common-table-expression netezza

我一直认为jsonLoader2.load("models/pic.json", addPicToScn); function addPicToScn(geometry, material) { var mtl = new THREE.MeshFaceMaterial(material); var mesh = new THREE.Mesh(geometry, mtl); mesh.scale.set(1.3, 1.3, 1.3); mesh.material.materials.forEach(function(m){ m.transparent = true; m.opacity = 0.1; }; mesh.castShadow = true; mesh.receiveShadow = true; mesh.rotation.set(2.8*Math.PI/5, 0, -Math.PI/2); mesh.position.set(0, 6, 21.8); scene.add(mesh); 子句作为一次性执行语句工作,它表现为普通表 - 你可以像在常规表上那样对其执行所有SQL操作。

但事实证明,在几个数据库(Oracle,Netezza,Sybase,Teradata)中,With子句在每次使用时都会执行。

with

上面的查询不是2个相同的数字,而是返回2个不同的数字,因此会为每个选择执行。

如果我在 With Test as( select random() --pseudo code ) select '1st select', * from Test union select '2nd select', * form Test 子句中有一个非常复杂的查询,并且我在查询的其余部分使用它5次,它将执行5次,这对我来说似乎非常无效。

有人能给我一个很好的逻辑理由吗?

3 个答案:

答案 0 :(得分:1)

oracle world中,如here所述,WITH query_name子句允许您为子查询块指定名称。然后,您可以通过指定查询名称来引用查询中的多个位置的子查询块。 Oracle通过将查询名称视为内联视图或临时表来优化查询。

您可以在任何顶级SELECT语句和大多数类型的子查询中指定此子句。查询名称对主查询和除定义查询名称本身的子查询之外的所有后续子查询可见。

如果在主查询的主体中需要多次使用WITH查询的结果,例如需要将一个平均值与两次或三次进行比较,则WITH子句最有价值。重点是尽量减少对多次连接到一个查询的表的访问次数。

子查询保理的限制:

您无法嵌套此子句。也就是说,您不能在另一个subquery_factoring_clause的子查询中指定subquery_factoring_clause。但是,在一个subquery_factoring_clause中定义的query_name可以在任何后续subquery_factoring_clause的子查询中使用。

在使用set运算符的查询中,set运算符子查询不能包含subquery_factoring_clause,但FROM子查询可以包含subquery_factoring_clause。

在您的情况下,您使用了一个随机函数,优化器会对其进行不同的处理,它会将其视为内联视图而不是具体化视图。正如@ ibre5041建议对不同的情况使用EXPLAIN PLAN

考虑递归CTE的情况,每次都在内部使用。

WITH generator ( value ) AS (
  SELECT 1 FROM DUAL
UNION ALL
  SELECT value + 1
  FROM   generator
  WHERE  value < 10
)
SELECT value
FROM   generator;

Plan hash value: 1492144221

--------------------------------------------------------------------------------------------------
| Id  | Operation                                 | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                          |      |     2 |    26 |     4   (0)| 00:00:01 |
|   1 |  VIEW                                     |      |     2 |    26 |     4   (0)| 00:00:01 |
|   2 |   UNION ALL (RECURSIVE WITH) BREADTH FIRST|      |       |       |            |          |
|   3 |    FAST DUAL                              |      |     1 |       |     2   (0)| 00:00:01 |
|*  4 |    RECURSIVE WITH PUMP                    |      |       |       |            |          |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - filter("VALUE"<10)

答案 1 :(得分:1)

至少在Teradata中它按预期工作,随机值只计算一次:

With Test as(
   select random(1,1000000) as x --pseudo code
)
select '1st select', x from Test
union
select '2nd select', x from Test
;

 *** Query completed. 2 rows found. 2 columns returned.
 *** Total elapsed time was 1 second.

'1st select'            x
------------  -----------
1st select         422654
2nd select         422654

答案 2 :(得分:0)

对于Oracle:

CTE aka Subquery factoring子句(在Oracle的术语中)可以是INLINEd或MATERIALIZEd,这是可行的。 CBO应该决定什么会更有效。你的ramdom()函数示例是一个极端情况。

尝试使用提示MATERIALIZE或INLINE来查看exec。计划变更。您的测试不表达任何有关实际SQL查询评估的行为。