【问题标题】:Oracle SQL Reuse sub query inside VIEWVIEW 中的 Oracle SQL Reuse 子查询
【发布时间】:2011-12-30 14:21:46
【问题描述】:

我正在尝试设置一个可能包含 1000 条记录的视图。某些字段需要返回完全相同数据的子查询。我想知道我是否可以在视图中查询一次,而不是每次都运行它。

以下是一些示例表/数据:

DROP VIEW MYVIEW;
DROP TABLE MYTABLE;
DROP TABLE MYTABLE_PARENT;

-- TABLES FOR VIEW
CREATE TABLE MYTABLE_PARENT ( PRIMARY_KEY NUMBER PRIMARY KEY );
CREATE TABLE MYTABLE ( PRIMARY_KEY NUMBER, MYVAL VARCHAR(255), PARENT_PRIMARY_KEY NUMBER);
INSERT INTO MYTABLE_PARENT VALUES (1);
INSERT INTO MYTABLE_PARENT VALUES (2);
INSERT INTO MYTABLE VALUES (1, 'MYVAL1-1', 1);
INSERT INTO MYTABLE VALUES (2, 'MYVAL1-2', 1);
INSERT INTO MYTABLE VALUES (3, 'MYVAL2-1', 2);

-- VIEW
CREATE OR REPLACE FORCE VIEW MYVIEW AS 
  SELECT CS.PRIMARY_KEY AS PARENT_PK,

  -- THE BELOW STATEMENTS REUSE THE SAME INNER SUBQUERY, IF THE 
  -- VIEW CONTAINS 1000 ROWS, THE INNER SUBQUERY WILL BE EXECUTED 
  -- 1000 TIMES, RETURNING THE SAME DATA EACH TIME.
  (SELECT PRIMARY_KEY FROM MYTABLE WHERE MYVAL = 'MYVAL1-1' AND 
  PARENT_PRIMARY_KEY = (SELECT PRIMARY_KEY FROM MYTABLE_PARENT 
  WHERE PRIMARY_KEY = CS.PRIMARY_KEY)) AS OUTPUT_VAL_1,

  (SELECT PRIMARY_KEY FROM MYTABLE WHERE MYVAL = 'MYVAL1-2' AND 
  PARENT_PRIMARY_KEY = (SELECT PRIMARY_KEY FROM MYTABLE_PARENT 
  WHERE PRIMARY_KEY = CS.PRIMARY_KEY)) AS OUTPUT_VAL_2
-- DEFINE CS
  FROM MYTABLE_PARENT CS;

SELECT * FROM MYVIEW;  

select 语句的结果如下:

PARENT_PK              OUTPUT_VAL_1           OUTPUT_VAL_2           
---------------------- ---------------------- ---------------------- 
1                      1                      2                      
2                                                                    

所以,在上面的查询中,我只想为视图中的每一行运行一次以下查询:

(SELECT PRIMARY_KEY FROM MYTABLE_PARENT WHERE PRIMARY_KEY = CS.PRIMARY_KEY)

有没有办法优化视图中的内部子查询?

【问题讨论】:

  • 为什么需要SELECT PRIMARY_KEY FROM MYTABLE_PARENT WHERE PRIMARY_KEY = CS.PRIMARY_KEY 查询?为什么不直接使用 CS.PRIMARY_KEY?

标签: sql oracle view inner-query


【解决方案1】:

对于 mytable 和 mytable_parent 的单个访问,请尝试:

CREATE OR REPLACE FORCE VIEW MYVIEW AS 
  SELECT CS.PRIMARY_KEY AS PARENT_PK,
         MAX(DECODE(MT.MYVAL, 'MYVAL1-1',MT.PRIMARY_KEY, TO_NUMBER(NULL))
                        AS OUTPUT_VAL_1,
         MAX(DECODE(MT.MYVAL, 'MYVAL1-2',MT.PRIMARY_KEY, TO_NUMBER(NULL))
                        AS OUTPUT_VAL_2
  FROM MYTABLE_PARENT CS
  LEFT JOIN MYTABLE MT ON MT.PARENT_PRIMARY_KEY = CS.PRIMARY_KEY AND
                          MT.MYVAL IN ('MYVAL1-1', 'MYVAL1-2')
  GROUP BY CS.PRIMARY_KEY

【讨论】:

    【解决方案2】:

    我现在无法对此进行测试,但请在视图的 SELECT 部分尝试此操作。我认为它至少会删除您的嵌套子查询。

    SELECT CS.PRIMARY_KEY AS PARENT_PK, mv1.PRIMARY_KEY AS OUTPUT_VAL_1, mv2.PRIMARY_KEY AS OUTPUT_VAL_2
    FROM MYTABLE_PARENT CS
    LEFT JOIN MYTABLE mv1 ON mv1.PARENT_PRIMARY_KEY = CS.PRIMARY_KEY
    LEFT JOIN MYTABLE mv2 ON mv2.PARENT_PRIMARY_KEY = CS.PRIMARY_KEY
    WHERE mv1.MYVAL = 'MYVAL1-1'
    AND mv2.MYVAL = 'MYVAL1-2';
    

    【讨论】:

    • 内连接假定总会有匹配的 mytable 记录——原始视图不一定正确。
    【解决方案3】:

    子查询如下:

    (SELECT PRIMARY_KEY FROM MYTABLE_PARENT WHERE PRIMARY_KEY = CS.PRIMARY_KEY)
    

    但别名 CS 也指向 MYTABLE_PARENT:

    MYTABLE_PARENT CS;
    

    所以整个子查询是多余的,你可以用CS.PRIMARY_KEY替换它?

    然后整个查询可以重写为:

    select    cs.primary_key as parent_pk
    ,         mt1.primary_key
    ,         mt2.primary_key
    from      mytable_parent cs
    join      mytable mt1
    on        mt.parent_primary_key = cs.primary_key
              and mt1.myval = 'myval1-1'
    join      mytable mt2
    on        mt2.parent_primary_key = cs.primary_key
              and mt2.myval = 'myval1-2'
    

    【讨论】:

    • 内连接假定总会有匹配的 mytable 记录——原始视图不一定正确。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多