sql優化:with as 作 union all的子查詢 來避免多次掃描表
語法:
1.結構: with 別名 as ( 公共sql片段 )
2.CTE(公共表示式)後面必須直接緊跟使用CTE的SQL語句,否則失效;
如:
1) with
cr as
(select
CountryRegionCode
from
person.CountryRegion
where
Name
like
'C%'
)
select
*
from
person.StateProvince
where
CountryRegionCode
in
(
select
*
from
cr) 有效
2) with
cr as
(select
CountryRegionCode
from
person.CountryRegion
where
Name
like
'C%'
)
select
*
from
person.StateProvince
select
*
from
person.StateProvince
where
CountryRegionCode
in
(
select
*
from
cr) 無效
3.CTE後面也可以跟其他的CTE,但只能使用一個
with
,多個CTE中間用逗號(,)分隔,如:
with
cte1
as
(select
*
from
table1
where
name
like
'abc%'
),
cte2
as
(select
*
from
table2
where
id > 20),
cte3
as
( select
*
from
table3
where
price < 100)
select
a.*
from
cte1 a, cte2 b, cte3 c
where
a.id = b.id
and
a.id = c.id
4.如果CTE的表示式名稱與某個資料表或檢視重名,則緊跟在該CTE後面的SQL語句使用的仍然是CTE,當然,後面的SQL語句使用的就是資料表或檢視了,如:
-- table1是一個實際存在的表
with
table1 as
( select
*
from
persons
where
age < 30 )
select
*
from
table1
-- 使用了名為table1的公共表表達式
select
*
from
table1
-- 使用了名為table1的資料表
5. CTE 可以引用自身,也可以引用在同一
WITH
子句中預先定義的CTE。不允許前向引用
6.不能在CTE_query_definition 中使用以下子句:
1)ORDER
BY
(除非指定了
TOP
子句)2)COMPUTE 或COMPUTE BY 3)INTO 4)帶有查詢提示的OPTION
子句 5)FOR
XML 6)FOR
BROWSE
7.
如果將CTE 用在屬於批處理的一部分的語句中,那麼在它之前的語句必須以分號結尾,如:
declare
@s nvarchar(3)
set
@s =
'C%'
;
-- 必須加分號
with
t_tree as
( select
CountryRegionCode
from
person.CountryRegion
where
Name
like
@s)
select
*
from
person.StateProvince
where
CountryRegionCode
in
(
select
*
from
t_tree)
與UNION ALL比較:
1.原sql ( union all ):
SELECT
0 REFUNDSUCCESSNUMBER,
0 REFUNDFAILNUMBER,
COUNT(ID) REFUNDNUMBER,
SUM(NVL(REFUND_AMOUNT, 0)) REFUNDAMOUNT,
SUM(NVL(POINT, 0)) REFUNDPOINTS,
CHANNEL,
GATEWAY_CODE GATEWAY
FROM PP_PAY
WHERE TRADE_TYPE = 1
AND CREATE_TIME >= TO_DATE('20180819', 'YYYYMMDD') AND
CREATE_TIME < TO_DATE('20180820', 'YYYYMMDD')
GROUP BY CHANNEL, GATEWAY_CODE
UNION ALL SELECT
COUNT(ID) REFUNDSUCCESSNUMBER,
0 REFUNDFAILNUMBER,
0 REFUNDNUMBER,
0 REFUNDAMOUNT,
0 REFUNDPOINTS,
CHANNEL,
GATEWAY_CODE GATEWAY
FROM PP_PAY
WHERE TRADE_TYPE = 1
AND REFUND_STATUS = 1 AND
CREATE_TIME >= TO_DATE('20180819', 'YYYYMMDD') AND CREATE_TIME < TO_DATE('20180820', 'YYYYMMDD')
GROUP BY CHANNEL, GATEWAY_CODE
UNION ALL SELECT
0 REFUNDSUCCESSNUMBER,
COUNT(ID) REFUNDFAILNUMBER,
0 REFUNDNUMBER,
0 REFUNDAMOUNT,
0 REFUNDPOINTS,
CHANNEL,
GATEWAY_CODE GATEWAY
FROM PP_PAY
WHERE TRADE_TYPE = 1
AND REFUND_STATUS >= 1 AND REFUND_STATUS <= 1 AND
CREATE_TIME >= TO_DATE('20180819', 'YYYYMMDD') AND CREATE_TIME < TO_DATE('20180820', 'YYYYMMDD')
GROUP BY CHANNEL, GATEWAY_CODE
2.用with as 替換後:
with refund as (select
0 REFUNDSUCCESSNUMBER,
0 REFUNDFAILNUMBER,
1 REFUNDNUMBER,
NVL(REFUND_AMOUNT, 0) REFUNDAMOUNT,
NVL(POINT, 0) POINT,
CHANNEL,
GATEWAY_CODE,
REFUND_STATUS
from ULEAPP_PAYMENT.PP_PAY
WHERE TRADE_TYPE = 1
AND CREATE_TIME >= TO_DATE('20180819', 'YYYYMMDD') AND
CREATE_TIME < TO_DATE('20180820', 'YYYYMMDD'))
SELECT
0 REFUNDSUCCESSNUMBER,
0 REFUNDFAILNUMBER,
COUNT(REFUNDNUMBER) REFUNDNUMBER,
SUM(NVL(REFUNDAMOUNT, 0)) REFUNDAMOUNT,
SUM(NVL(POINT, 0)) REFUNDPOINTS,
CHANNEL,
GATEWAY_CODE
FROM refund
GROUP BY CHANNEL, GATEWAY_CODE
UNION ALL SELECT
COUNT(REFUNDSUCCESSNUMBER) REFUNDSUCCESSNUMBER,
0 REFUNDFAILNUMBER,
0 REFUNDNUMBER,
0 REFUNDAMOUNT,
0 REFUNDPOINTS,
CHANNEL,
GATEWAY_CODE
FROM refund
WHERE REFUND_STATUS = 1
GROUP BY CHANNEL, GATEWAY_CODE
UNION ALL SELECT
0 REFUNDSUCCESSNUMBER,
COUNT(REFUNDFAILNUMBER) REFUNDFAILNUMBER,
0 REFUNDNUMBER,
0 REFUNDAMOUNT,
0 REFUNDPOINTS,
CHANNEL,
GATEWAY_CODE
FROM refund
WHERE REFUND_STATUS >= 1 and REFUND_STATUS <= 1
GROUP BY CHANNEL, GATEWAY_CODE
該表開發庫資料量10w條,CREATE_TIME索引生效,替換後查詢速度提提升在1倍以上。