调整内部视图查询有哪些不同的方法?

时间:2017-01-11 15:20:03

标签: sql oracle oracle11g

要调整的查询如下。

查询的输入为year_Month='201507'

    SELECT A.account_number,
      A.market,
      A.security_type,
      A.total_market_value,
      A.max_event_Date,
      -- first inner Query
(SELECT COUNT(*)
      FROM MIGC_ACCOUNT_STATEMENT acctStmt
      WHERE acctStmt.account_number   =A.account_number
      AND acctStmt.market             =A.market
      AND acctStmt.security_type      =A.security_type
      AND acctStmt.year_Month         =A.year_Month
      AND acctStmt.ACCOUNT_EVENT_DATE = A.max_event_Date
      ) AS isincount,
       -- second inner Query
      (SELECT COUNT(COUNT(*))
      FROM MIGC_ACCOUNT_STATEMENT acctStmt
      WHERE acctStmt.account_number =A.account_number
      AND acctStmt.market           =A.market
      AND(( acctStmt.security_type  =A.security_type)
      OR (acctStmt.security_type   IS NULL))
      AND acctStmt.year_Month       =A.year_Month
      GROUP BY acctStmt.ACCOUNT_EVENT_DATE
      ) AS totalcount,
      -- 3rd inner Query
      (SELECT COUNT(*)
      FROM MIGC_ACCOUNT_STATEMENT acctStmt
      WHERE acctStmt.account_number   =A.account_number
      AND acctStmt.market             =A.market
      AND acctStmt.security_type      =A.security_type
      AND acctStmt.year_Month         =A.year_Month
      AND acctStmt.ACCOUNT_EVENT_DATE = A.max_event_Date
      AND acctStmt.market_value       = 0
      ) AS zero_market_value,
     -- 4th inner Query
      (SELECT SUM(acctStmt.market_value)
      FROM MIGC_ACCOUNT_STATEMENT acctStmt
      WHERE acctStmt.account_number   =A.account_number
      AND acctStmt.market             =A.market
      AND acctStmt.security_type      =A.security_type
      AND acctStmt.ACCOUNT_EVENT_DATE =A.max_event_Date
      AND acctStmt.year_Month         =A.year_Month
      GROUP BY acctStmt.account_number,
        acctStmt.security_type,
        acctStmt.market
      ) AS mon_end_value
    FROM
--inner view
      (SELECT account_number,
        market,
        security_type,
        SUM(market_value)       AS total_market_value,
        MAX(ACCOUNT_EVENT_DATE) AS max_event_Date,
        year_Month
      FROM MIGC_ACCOUNT_STATEMENT
      WHERE year_Month   ='201507'
      AND security_Type IS NOT NULL
      GROUP BY account_number,
        market,
        security_type,
        year_Month
      ) A 

我的表格结构如下

CREATE TABLE MIGC_ACCOUNT_STATEMENT"
  (
    "ID"         VARCHAR2(15 CHAR) NOT NULL ENABLE,
    "REQUEST_ID" VARCHAR2(100 CHAR),
    "REQUEST_DATE" TIMESTAMP (6),
    "PRODUCT_GROUP"     VARCHAR2(50 CHAR),
    "SOURCE_SYSTEM"     VARCHAR2(3 CHAR),
    "PROCESSED_BY_SITE" VARCHAR2(50 CHAR),
    "ACCOUNT_EVENT_DATE" DATE,
    "ACCOUNT_NUMBER" VARCHAR2(50 CHAR),
    "SECURITY_ID"    VARCHAR2(50 CHAR),
    "SECURITY_TYPE"  VARCHAR2(100 CHAR),
    "SECURITY_NAME"  VARCHAR2(200 CHAR),
    "SECURITY_PRICE" NUMBER,
    "SECURITY_PRICE_DATE" DATE,
    "QUANTITY"              NUMBER,
    "MARKET_VALUE_CURRENCY" VARCHAR2(5 CHAR),
    "MARKET"                VARCHAR2(100 CHAR),
    "MARKET_VALUE"          NUMBER,
    "SECURITY_ID_TYPE"      VARCHAR2(50 CHAR),
    "LOB_ID"                VARCHAR2(20 CHAR),
    "YEAR_MONTH"            NUMBER,
    "BATCH_NUMBER"          NUMBER NOT NULL ENABLE,
    "CUSTOMER_ID"           VARCHAR2(50 CHAR)    
  )

Id是主键。我检查了查询成本,它非常高。

2 个答案:

答案 0 :(得分:1)

评论太长了。

首先,您应该将用于关联的所有列索引 - 一个索引,使用复合键。所以:MIGC_ACCOUNT_STATEMENT(account_number, acctStmt.market, security_type, year_Month, ACCOUNT_EVENT_DAT)是第一个的最佳索引。

其次,请勿使用COUNT(COUNT(*))。我的猜测是,即使是真正理解该构造的Oracle爱好者仍然会发现COUNT(DISTINCT acctStmt.ACCOUNT_EVENT_DATE)更清楚。 (注意:这些不完全相同,因为您的版本计算NULL。我猜不会发生这种情况。)

答案 1 :(得分:0)

我认为你可以通过使用条件分析函数来避免同一个表的多个表查找,如下所示:

SELECT account_number,
       market,
       security_type,
       SUM(CASE WHEN a.security_type is not NULL THEN market_value END) AS total_market_value,
       isincount,
       totalcount,
       zero_market_value,
       mon_end_value
FROM   (SELECT a.account_number,
               a.market,
               a.security_type,
               a.max_event_date,
               COUNT(CASE WHEN a.security_type is not NULL
                               AND a.account_event_date = max_event_date THEN ID END)
                 OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS isincount,
               COUNT(DISTINCT NVL(a.account_event_date, DATE '1800-01-01'))
                 OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS totalcount,
               COUNT(CASE WHEN a.security_type is not NULL
                               AND a.account_event_date = max_event_date 
                               AND a.market_value = 0 THEN ID END)
                 OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS zero_market_value,
               SUM(CASE WHEN a.security_type is not NULL
                             AND a.account_event_date = max_event_date THEN a.market_value END)
                 OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS mon_end_value
        FROM   --inner view
              (SELECT id,
                      account_number,
                      market,
                      security_type,
                      market_value,
                      MAX(account_event_date) OVER (PARTITION BY BY account_number, market, security_type, year_month) AS max_event_date,
                      year_month
               FROM   migc_account_statement
               WHERE  year_month = 201507)) a
GROUP BY account_number,
         market,
         security_type,
         isincount,
         totalcount,
         zero_market_value,
         mon_end_value;

为了便于阅读,我建议使用子查询因子(又名with子句,又名Common Table Expressions又称CTE),所以它看起来像:

WITH results_with_max_dt AS (SELECT id,
                                    account_number,
                                    market,
                                    security_type,
                                    market_value,
                                    MAX(account_event_date) OVER (PARTITION BY BY account_number, market, security_type, year_month) AS max_event_date,
                                    year_month
                             FROM   migc_account_statement
                             WHERE  year_month = 201507),
      conditional_values AS (SELECT a.account_number,
                                    a.market,
                                    a.security_type,
                                    a.max_event_date,
                                    COUNT(CASE WHEN a.security_type is not NULL
                                                    AND a.account_event_date = max_event_date THEN ID END)
                                      OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS isincount,
                                    COUNT(DISTINCT NVL(a.account_event_date, DATE '1800-01-01'))
                                      OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS totalcount,
                                    COUNT(CASE WHEN a.security_type is not NULL
                                                    AND a.account_event_date = max_event_date 
                                                    AND a.market_value = 0 THEN ID END)
                                      OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS zero_market_value,
                                    SUM(CASE WHEN a.security_type is not NULL
                                                  AND a.account_event_date = max_event_date THEN a.market_value END)
                                      OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS mon_end_value
                             FROM   results_with_max_dt a)
SELECT account_number,
       market,
       security_type,
       SUM(CASE WHEN a.security_type is not NULL THEN market_value END) AS total_market_value,
       isincount,
       totalcount,
       zero_market_value,
       mon_end_value
FROM   conditional_values
GROUP BY account_number,
         market,
         security_type,
         isincount,
         totalcount,
         zero_market_value,
         mon_end_value;

N.B。以上查询未经测试。另请注意,我已从201507年左右删除了单引号,因为根据您提供的表格DDL,year_month列的数据类型为NUMBER