【问题标题】:Oracle SQL query with CASE WHEN EXISTS subquery optimizationOracle SQL 查询与 CASE WHEN EXISTS 子查询优化
【发布时间】:2016-02-23 00:53:14
【问题描述】:

我正在使用以下查询在 Oracle 11g (11.2.0.3.0) 中创建视图。

CREATE OR REPLACE FORCE VIEW V_DOCUMENTS_LIST
(
   ID_DOC,
   ATTACHMENTS_COUNT,
   TOTAL_DIMENSION,
   INSERT_DATE,
   ID_STATE,
   STATE,
   ID_INSTITUTE,
   INSTITUTE,
   HASJOB
)
AS
    SELECT D.ID_DOC,
        COUNT (F.ID_FILE) AS ATTACHMENTS_COUNT,
        CASE
           WHEN SUM (F.DIMENSION) IS NULL THEN 0
           ELSE SUM (F.DIMENSION)
        END
           AS TOTAL_DIMENSION,
        D.INSERT_DATE,
        D.ID_STATE,
        S.STATE_DESC AS STATE,
        D.ID_INSTITUTE,
        E.NAME AS INSTITUTE,
        CASE
           WHEN EXISTS (SELECT D.ID_DOC FROM JOB) THEN 'true'
           ELSE 'false'
        END
           AS HASJOB
    FROM DOCUMENTS D
        LEFT JOIN FILES F ON D.ID_DOC = F.ID_DOC
        JOIN STATES S ON D.ID_STATE = S.ID_STATE
        JOIN INSTITUTES E ON D.ID_INSTITUTE = E.ID_INSTITUTE
    GROUP BY D.ID_DOC,
        D.INSERT_DATE,
        D.ID_STATE,
        S.STATE_DESC,
        D.ID_INSTITUTE,
        E.NAME;

然后我查询该视图以获取ASPX 页面中DataGridView 的值。

SELECT * 
FROM V_DOCUMENTS_LIST
ORDER BY ID_STATE DESC, INSTITUTE, INSERT_DATE DESC;

相关表和关系

文件;文件;工作;

文档 (1-1) (0-N) 文件

工作 (0-1) (0-N) 文件

查询视图,我得到完整的文档列表及其所有相关信息(ID、描述、日期、状态等)以及每个文档:

  • 附件总数
  • 附加文件的总尺寸(以字节为单位)
  • 布尔值,表示是否至少有一个 JOB DOCUMENT 或不相关

在视图包含几千条记录之前,一切正常。现在记录数量正在增加,视图上的SELECT * FROM 大约需要 2:30 分钟,有 15.000-20.000 条记录。 我知道我的视图中一个非常耗时的部分是嵌套的SELECT

CASE
    WHEN EXISTS (SELECT D.ID_DOC FROM JOB) THEN 'true'
    ELSE 'false'
END
AS HASJOB

如何优化我的视图?

【问题讨论】:

  • 请与我们分享执行计划。

标签: oracle subquery query-optimization select-case


【解决方案1】:

您要对表 JOB 进行完整索引,将 WHERE 子句放入查询中:

SELECT D.ID_DOC FROM JOB

【讨论】:

    【解决方案2】:

    为了解决不存在的问题,您可以添加一个联接:

    LEFT JOIN (select distinct id_doc from JOB) J
    ON d.id_doc = J.id_doc
    

    Has_job 列将是:

        CASE
           WHEN j.id_doc is not null THEN 'true'
           ELSE 'false'
        END AS HASJOB
    

    PS:您当前的实现存在问题,因为如果作业表有行,SELECT D.ID_DOC FROM JOB 将始终包含行。它等同于select * from job,因为存在只是测试行的存在。逻辑上正确的实现是:SELECT 1 FROM JOB j where j.id_doc = D.ID_DOC

    【讨论】:

    • 两种解决方案都运行良好。 1)LEFT JOINJOBS 表,然后使用您的CASE 语句。 2) 将我的CASE 声明与您的SELECT 1 FROM JOBS J WHERE J.ID_DOC = D.ID_DOC 一起保留,而不加入JOBS 表。两者都表现不错。相同的执行时间。谢谢!
    猜你喜欢
    • 2021-03-15
    • 2017-05-30
    • 1970-01-01
    • 2017-08-15
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多