今天开发找到我说一条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
比如你需要视图随机返回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等需要从业务的角度改写,在设计视图的时候也一定要避免