【问题标题】:Force Oracle to use filtering in START WITH from outside of query强制 Oracle 从查询外部在 START WITH 中使用过滤
【发布时间】:2016-05-31 05:45:38
【问题描述】:

表定义:

  create table Tree
  (node varchar2(20),
  parentNode varchar2(20),
  val number);

  create index idx_tree_01 on Tree
  (node );
   create index idx_tree_02 on Tree
  (parentnode); 

样本数据:

Insert into TREE (NODE,PARENTNODE,VAL) values ('2','1',2);
Insert into TREE (NODE,PARENTNODE,VAL) values ('3','2',3);
Insert into TREE (NODE,PARENTNODE,VAL) values ('4','2',3);
Insert into TREE (NODE,PARENTNODE,VAL) values ('5','4',1);
Insert into TREE (NODE,PARENTNODE,VAL) values ('6','3',1);

查看定义:

 create view tree_view as 
     select connect_by_root parentnode as firstNode,
      lpad(' ', 2 * level - 2, ' ') || val as MyVal,
      node, parentNode
   from tree 
   start with parentnode in ( select parentnode from tree) 
   connect by parentnode = prior node

现在我要执行查询:

select * from tree_view 
where firstNode = '1'

查询的执行计划是:

-------------------------------------------------------------------------
| Id  | Operation                                | Name        | E-Rows |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT                         |             |        |
|*  1 |  VIEW                                    | TREE_VIEW   |      5 |
|*  2 |   CONNECT BY NO FILTERING WITH START-WITH|             |        |
|   3 |    TABLE ACCESS FULL                     | TREE        |      5 |
|*  4 |    INDEX RANGE SCAN                      | IDX_TREE_02 |      1 |
-------------------------------------------------------------------------

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

   1 - filter("FIRSTNODE"='1')
   2 - access("PARENTNODE"=PRIOR NULL)
       filter( IS NOT NULL)
   4 - access("PARENTNODE"=:B1)

如您所见,最后使用了filterfirstnode = '1'。我希望它被用作第一件事..

不能修改视图(我只能添加一些提示)。

如何提示 Oracle 在 START WITH 中使用 firstNode 值?它将带来很大的性能改进。

我真正的“树”表是几个表,数据量很大。 正如我提到的,我无法修改视图。

不要向我求婚:

  • 带有 firstnode 参数和流水线结果的函数
  • 修改视图以在开头使用会话上下文
  • 开头的临时表队列
  • 等。

视图必须相同。仅允许使用提示。

【问题讨论】:

  • @PavelGatnar 我不会在这里问什么时候会有这种可能性。该项目已上线 - 不允许进行较大的修改。
  • 只是示例。在现实中,有来自其他表的结果。请注意我的问题是如何将过滤从查询之外移到 START WITH。
  • 你解决了吗?你能说出你尝试了哪些提示吗?

标签: sql oracle oracle11g database-performance connect-by


【解决方案1】:

first_node 是视图中的一列,由connect_by_root() 运算符生成。 documentation says of this operator:

您不能在START WITH 条件或CONNECT BY 条件中指定此运算符。

因此,无论如何都无法实现您想要的。如果你仔细想想,这不是不合理的:要派生第一个节点,查询必须遍历整个层次结构以找到每个叶子的根节点。

一种调优方法 - 虽然可能不是一种对您开放的方法 - 是使用传递闭包实现层次结构。查看this other SO thread.

【讨论】:

  • 递归 CTE 怎么样?你认为那里可能吗? with tv (firstNode, val, node ,parentNode, lvl) as ( select parentnode as firstNode, val , node, parentNode, 0 as lvl from tree union all select tv.firstNode, tr.val, tr.node, tr.parentNode, lvl + 1 from tv join tree tr on tv.node = tr.parentnode ) select * from tv where firstNode = '1'
  • @APC,您可以查看我的答案吗?
【解决方案2】:

您可以尝试创建 PIPELINED 函数来返回视图行

CREATE TYPE t_row AS OBJECT (
  first_name  VARCHAR2(1000),
  my_val      VARCHAR2(1000)
  ... 
  );

CREATE TYPE t_tab IS TABLE OF t_row;

CREATE OR REPLACE FUNCTION get_hierarchy RETURN t_tab PIPELINED
IS
BEGIN
    FOR rec IN (SELECT ...) LOOP
      PIPE ROW (t_row(rec.firstNode, rec.myval, ...));
    END LOOP;
RETURN;
END get_hierarchy;

并重写查询

SELECT *
  FROM TABLE(get_hierarchy)

【讨论】:

  • 我写道,这不是问题的解决方案。抱歉,您浪费时间写答案。
  • @dcieslak 但是你可以在函数的选择中使用未修改的视图,为什么不呢?
  • 它的调用方式必须保持不变。您的解决方案首先是我向客户提出的,但被拒绝了。下一个是使用应用程序上下文——视图保持不变——但它也被拒绝了。我猜 APC 是对的,无法调优..
  • @dcieslak 我现在明白了。删除我的答案合适吗?
  • 你可以保留它。最后,我会对所有有意义且可能对其他人有用的内容进行投票。
【解决方案3】:

你会满意吗?

SELECT DISTINCT *
FROM tree_view 
START WITH firstNode = '1'
CONNECT BY parentnode = PRIOR node

 Plan Hash Value  : 2532164387 

-----------------------------------------------------------------------------------------------------
| Id  | Operation                                    | Name        | Rows | Bytes | Cost | Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                             |             |    5 | 10090 |    4 | 00:00:01 |
|   1 |   HASH UNIQUE                                |             |    5 | 10090 |    4 | 00:00:01 |
| * 2 |    CONNECT BY NO FILTERING WITH SW (UNIQUE)  |             |      |       |      |          |
|   3 |     VIEW                                     | TREE_VIEW   |    5 | 10190 |    4 | 00:00:01 |
| * 4 |      CONNECT BY NO FILTERING WITH START-WITH |             |      |       |      |          |
|   5 |       TABLE ACCESS FULL                      | TREE        |    5 |    35 |    3 | 00:00:01 |
| * 6 |       INDEX RANGE SCAN                       | IDX_TREE_02 |    1 |     2 |    1 | 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 2 - access("T"."PARENTNODE"=PRIOR "T"."NODE")
* 2 - filter("FIRSTNODE"='1')
* 4 - access("PARENTNODE"=PRIOR "NODE")
* 4 - filter( EXISTS (SELECT 0 FROM TESTER."TREE" "TREE" WHERE "PARENTNODE"=:B1))
* 6 - access("PARENTNODE"=:B1)

区别在第 4 行:filter( EXISTS (SELECT 0 FROM TESTER."TREE" "TREE" WHERE "PARENTNODE"=:B1)) 此查询返回重复数据。 DISTINCT 是保持相同结果集所必需的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 2021-02-23
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 2022-12-06
    相关资源
    最近更新 更多