脑残设计-视图里包含order by和union

今天开发找到我说一条SQL执行的特别慢。SQL里面有一张视图,视图单拿出来跑,需要十几分钟才能出结果(从这里基本上可以定位是视图的问题了)。

SQL和 视图的定义 如下

WITH 
"VW_RPT_MID_SUM_TABLE0" AS 
    (
    SELECT
        "VW_RPT_MID_SUM_TABLE"."AS_OF_DATE" AS "AS_OF_DATE", 
        "VW_RPT_MID_SUM_TABLE"."ORG_UNIT_ID" AS "ORG_UNIT_ID", 
        "VW_RPT_MID_SUM_TABLE"."CURRENCY_CD" AS "CURRENCY_CD", 
        "VW_RPT_MID_SUM_TABLE"."EXPENSES04" AS "EXPENSES04", 
        "VW_RPT_MID_SUM_TABLE"."EXPENSES05" AS "EXPENSES05", 
        "VW_RPT_MID_SUM_TABLE"."EXPENSES06" AS "EXPENSES06", 
        "VW_RPT_MID_SUM_TABLE"."EXPENSES07" AS "EXPENSES07", 
        "VW_RPT_MID_SUM_TABLE"."EXPENSES08" AS "EXPENSES08", 
        "VW_RPT_MID_SUM_TABLE"."EXPENSES09" AS "EXPENSES09", 
        "VW_RPT_MID_SUM_TABLE"."EXPENSES10" AS "EXPENSES10", 
        "VW_RPT_MID_SUM_TABLE"."ORG_L1" AS "ORG_L1", 
        "VW_RPT_MID_SUM_TABLE"."ORG_L2" AS "ORG_L2", 
        "VW_RPT_MID_SUM_TABLE"."DATA_TYPE" AS "DATA_TYPE"
    FROM
        "ANNE_APPS".VW_RPT_MID_SUM_TABLE "VW_RPT_MID_SUM_TABLE" 
    WHERE 
        "VW_RPT_MID_SUM_TABLE"."ORG_L1" = 'T024' AND
        ("VW_RPT_MID_SUM_TABLE"."AS_OF_DATE" = '201703' AND
        "VW_RPT_MID_SUM_TABLE"."DATA_TYPE" = 'B' AND
        'T01' = 'CNY' AND
        "VW_RPT_MID_SUM_TABLE"."CURRENCY_CD" = 'CNY' OR
        'T01' = 'R01' AND
        "VW_RPT_MID_SUM_TABLE"."CURRENCY_CD" <> 'CNY' OR
        'T01' = 'T01' AND
        1 = 1)
    ), 
"管会事实数据" AS 
    (
    SELECT
        "VW_RPT_MID_SUM_TABLE0"."AS_OF_DATE" AS "日期", 
        "VW_RPT_MID_SUM_TABLE0"."DATA_TYPE" AS "数据类型", 
        "VW_RPT_MID_SUM_TABLE0"."ORG_UNIT_ID" AS "机构", 
        "VW_RPT_MID_SUM_TABLE0"."CURRENCY_CD" AS "币种", 
        "VW_RPT_MID_SUM_TABLE0"."EXPENSES04" AS "营业费用04", 
        "VW_RPT_MID_SUM_TABLE0"."EXPENSES05" AS "营业费用05", 
        "VW_RPT_MID_SUM_TABLE0"."EXPENSES06" AS "营业费用06", 
        "VW_RPT_MID_SUM_TABLE0"."EXPENSES07" AS "营业费用07", 
        "VW_RPT_MID_SUM_TABLE0"."EXPENSES08" AS "营业费用08", 
        "VW_RPT_MID_SUM_TABLE0"."EXPENSES09" AS "营业费用09", 
        "VW_RPT_MID_SUM_TABLE0"."EXPENSES10" AS "营业费用10"
    FROM
        VW_RPT_MID_SUM_TABLE0
    ), 
"ORG4" AS 
    (

    SELECT
        "DIM_TREE_3"."LEVEL_01_CODE" AS "LEVEL_01_CODE", 
        "DIM_TREE_3"."LEVEL_02_CODE" AS "LEVEL_02_CODE", 
        "DIM_TREE_3"."LEAF_CODE" AS "LEAF_CODE"
    FROM
        "ANNE_APPS"."VW_DIM_TREE_3" "DIM_TREE_3" 
    WHERE 
        "DIM_TREE_3"."LEVEL_01_CODE" = 'T024'
    ), 
"机构" AS 
    (
    SELECT
        "ORG4"."LEVEL_01_CODE" AS "一级机构编号", 
        "ORG4"."LEAF_CODE" AS "三级机构编号"
    FROM
        "ORG4"
    )
SELECT
    "机构"."一级机构编号" AS "column0", 
    CASE (SUM("管会事实数据"."营业费用04") + SUM("管会事实数据"."营业费用05")) + SUM("管会事实数据"."营业费用06")
        WHEN 0 THEN ((SUM("管会事实数据"."营业费用04") + SUM("管会事实数据"."营业费用05")) + SUM("管会事实数据"."营业费用06")) + SUM("管会事实数据"."营业费用10")
        ELSE ((SUM("管会事实数据"."营业费用07") + SUM("管会事实数据"."营业费用08")) + SUM("管会事实数据"."营业费用09")) + SUM("管会事实数据"."营业费用10")
    END AS "column1"
FROM
    "管会事实数据"
        INNER JOIN "机构"
        ON "管会事实数据"."机构" = "机构"."三级机构编号" 
WHERE 
    "管会事实数据"."数据类型" = 'B' AND
    "管会事实数据"."日期" = '201703' AND
    ('T01' = 'CNY' AND
    "管会事实数据"."币种" = 'CNY' OR
    'T01' = 'R01' AND
    "管会事实数据"."币种" <> 'CNY' OR
    'T01' = 'T01' AND
    1 = 1) 
GROUP BY 
    "机构"."一级机构编号"


CREATE OR REPLACE VIEW VW_RPT_MID_SUM_TABLE AS
SELECT
  to_char(AS_OF_DATE,'YYYYMM') AS AS_OF_DATE,
  ORG_UNIT_ID ,
  LOB_ID ,
  PROD_ID ,
  CURRENCY_CD ,
  BIZ_ENTITY_ID ,
  CHANNEL ,
  INDUSTRY ,
  CORP_SIZE_CD ,
  CUST_TYPE ,
  STRATEGIC_CORP_FLAG ,
  ACCT_BAL,
  DAILY_AVG_BAL ,
  EXTNL_INTEREST_INCM ,
  EXTNL_INTEREST_EXPNS ,
  TRANS_AMT ,
  TRANS_CNT ,
  FTP_INCM ,
  FTP_EXPNS ,
  FTP_INT_AJUST ,
  I_BIZ_INCM ,
  I_BIZ_EXPNS ,
  INVESTMENT_INCM ,
  FAIR_VALUE_CHANGED_INCM ,
  EXCHANGE_INCM ,
  BIZ_TAX_SURCHARGE ,
  OTH_OPERATING_INCM ,
  OTH_OPERATING_EXPNS ,
  ASSET_LOSS_PRVS ,
  NON_OPERATING_INCM ,
  NON_OPERATING_EXPNS ,
  EXPENSES01,
  EXPENSES02,
  EXPENSES03 ,
  EXPENSES04 ,
  EXPENSES05 ,
  EXPENSES06 ,
  EXPENSES07 ,
  EXPENSES08 ,
  EXPENSES09 ,
  EXPENSES10 ,
  EXPENSES11 ,
  EXPENSES12 ,
  EXPENSES13 ,
  EXPENSES14 ,
  EXPENSES15 ,
  PRE_TAX_PROFIT ,
  INCM_TAX ,
  NET_PROFIT ,
  CREDIT_RISK_CAPITAL ,
  OPERATIONAL_RISK_CAPITAL ,
  MARKET_RISK_CAPITAL ,
  CAPITAL_COST ,
  ECONOMIC_VALUE_ADDED ,
  ORG_L1 ,
  ORG_L2,
  DEPO_ACCT_BAL,
  DEPO_AVG_BAL,
  AGGR_ACCT_BAL,
  AGGR_AVG_BAL,
  LOAN_ACCT_BAL,
  LOAN_AVG_BAL,
  PURE_LOAN_ACCT_BAL,
  PURE_LOAN_AVG_BAL,
  MGR_TYPE,
  'A' as DATA_TYPE,
  A_ACCT_BAL,
  A_DAILY_AVG_BAL,
  L_ACCT_BAL,
  L_DAILY_AVG_BAL,
         corp_cur_dp_bal,
       corp_cur_dp_avg,
       corp_term_dp_bal,
       corp_term_dp_avg,
       indv_cur_dp_bal,
       indv_cur_dp_avg,
       indv_term_dp_bal,
       indv_term_dp_avg,
       downpay_cur_dp_bal,
       downpay_cur_dp_avg,
       downpay_term_dp_bal,
       downpay_term_dp_avg,
       fin_mark_dp_bal,
       fin_mark_dp_avg,
       structure_dp_bal,
       structure_dp_avg,
       structure_dp_corp_bal,
       structure_dp_corp_avg,
       wealthy_mgmt_bal,
       wealthy_mgmt_avg,
  rwa_weight
 from ANNE_RPT.RPT_MID_SUM_TABLE
 union
 SELECT
  to_char(AS_OF_DATE,'YYYYMM') AS AS_OF_DATE,
  ORG_UNIT_ID ,
  LOB_ID ,
  PROD_ID ,
  CURRENCY_CD ,
  BIZ_ENTITY_ID ,
  CHANNEL ,
  INDUSTRY ,
  CORP_SIZE_CD ,
  CUST_TYPE ,
  STRATEGIC_CORP_FLAG ,
  ACCT_BAL,
  DAILY_AVG_BAL ,
  EXTNL_INTEREST_INCM ,
  EXTNL_INTEREST_EXPNS ,
  TRANS_AMT ,
  TRANS_CNT ,
  FTP_INCM ,
  FTP_EXPNS ,
  FTP_INT_AJUST ,
  I_BIZ_INCM ,
  I_BIZ_EXPNS ,
  INVESTMENT_INCM ,
  FAIR_VALUE_CHANGED_INCM ,
  EXCHANGE_INCM ,
  BIZ_TAX_SURCHARGE ,
  OTH_OPERATING_INCM ,
  OTH_OPERATING_EXPNS ,
  ASSET_LOSS_PRVS ,
  NON_OPERATING_INCM ,
  NON_OPERATING_EXPNS ,
  EXPENSES01,
  EXPENSES02,
  EXPENSES03 ,
  EXPENSES04 ,
  EXPENSES05 ,
  EXPENSES06 ,
  EXPENSES07 ,
  EXPENSES08 ,
  EXPENSES09 ,
  EXPENSES10 ,
  EXPENSES11 ,
  EXPENSES12 ,
  EXPENSES13 ,
  EXPENSES14 ,
  EXPENSES15 ,
  PRE_TAX_PROFIT ,
  INCM_TAX ,
  NET_PROFIT ,
  CREDIT_RISK_CAPITAL ,
  OPERATIONAL_RISK_CAPITAL ,
  MARKET_RISK_CAPITAL ,
  CAPITAL_COST ,
  ECONOMIC_VALUE_ADDED ,
  ORG_L1 ,
  ORG_L2,
  DEPO_ACCT_BAL,
  DEPO_AVG_BAL,
  AGGR_ACCT_BAL,
  AGGR_AVG_BAL,
  LOAN_ACCT_BAL,
  LOAN_AVG_BAL,
  PURE_LOAN_ACCT_BAL,
  PURE_LOAN_AVG_BAL,
  MGR_TYPE,
  'B' as DATA_TYPE,
  A_ACCT_BAL,
  A_DAILY_AVG_BAL,
  L_ACCT_BAL,
  L_DAILY_AVG_BAL,
         corp_cur_dp_bal,
       corp_cur_dp_avg,
       corp_term_dp_bal,
       corp_term_dp_avg,
       indv_cur_dp_bal,
       indv_cur_dp_avg,
       indv_term_dp_bal,
       indv_term_dp_avg,
       downpay_cur_dp_bal,
       downpay_cur_dp_avg,
       downpay_term_dp_bal,
       downpay_term_dp_avg,
       fin_mark_dp_bal,
       fin_mark_dp_avg,
       structure_dp_bal,
       structure_dp_avg,
       structure_dp_corp_bal,
       structure_dp_corp_avg,
       wealthy_mgmt_bal,
       wealthy_mgmt_avg,
  rwa_weight
 from ANNE_RPT.RPT_MID_SUM_TABLE_Y
 order by AS_OF_DATE desc;

视图里面的表数据量如下:

SELECT COUNT(1) FROM ANNE_RPT.RPT_MID_SUM_TABLE_Y;    ---14754409
SELECT COUNT(1) FROM ANNE_RPT.RPT_MID_SUM_TABLE;         ---10726835

视图里面有order by 这是其一坑

视图里面有union 这是其二坑

union 自带order by作用,这里面居然在结尾加了一个order by ,首先从语意上说这个order by没有任何意义

视图里面有order by本身也是脑残设计,如果确实需要order by可以拿到视图外面去order by

视图里面有order by 。每当访问这个视图的时候,视图都需要先order by【order by的主要消耗来自于table access full】再返回数据。不管外面SQL是否需要order by

扫描二维码关注公众号,回复: 2420149 查看本文章

比如你需要视图随机返回10行数据where rownum<=10 ,视图内部会先table access full两个表返回2000w行数据进行order by,再返回10行

所以坑不言而喻

同理 :union 比order by还要坑,union 首先需要排序两个大表,然后再去重!!!!

所以到这里我们基本上就有思路了

1.把order by去掉  【任何视图里面都不应该有order by】

2.union改为union all 当然这样改,逻辑就变了。

但是对整个查询没有影响。因为view中union 上下部分别有'A' as DATA_TYPE, 'B' as DATA_TYPE,这种打标可见想对表是单独访问

我把猜想和开发确认,确实如此,页面上有下拉框限制只访问一个表。

修改完后,原SQL 1s响应

总结:视图中有 order by、union、distinct、rownum等需要从业务的角度改写,在设计视图的时候也一定要避免


猜你喜欢

转载自blog.csdn.net/skybig1988/article/details/71123556