oracle sql 高階程式設計學習筆記(二十三)
繼上一篇中講到model子句的效能優化,本文將繼續學習model子句查詢重寫的優化:
一、謂語前推
1、例項演示:
select * from (select product, country, year, week, inventory, sale, receipts
from sales_fact
model return updated rows
partition by(product, country)
dimension by(year, week)
measures(0 inventory, sale, receipts)
rules automatic order
(inventory [ year, week ] order by year,week asc
= nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]
)
order by product, country, year, week)
where
--把謂詞放到檢視外面,看執行計劃是否能進行謂詞推進
country = 'Australia'
and product = 'Xtend Memory' ;
很明顯第四步中兩個謂詞都推進了檢視中,先進行了謂詞篩選,然後在結果集中應用了model子句,
這樣相對於model子句是非常小的資料行集
2 、沒有進行謂詞推進
我們把上一步中的謂詞改為year=’2000’
select * from (select product, country, year, week, inventory, sale, receipts
from sales_fact
model return updated rows
partition by(product, country)
dimension by(year, week)
measures(0 inventory, sale, receipts)
rules automatic order
(inventory [ year, week ] order by year,week asc
= nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]
)
order by product, country, year, week)
where year='2000';
第四部中並沒有進行謂詞篩選,二十全表掃描得到111k行資料,model子句需要處理這些資料後
再進行謂詞篩選
二、物化檢視重寫
一般來說分割槽列上的的謂詞都可以安全地推進到檢視中,但並不是所有維度列上的謂詞都可以進行推進;
–建立物化檢視
create materialized view mv_model_inventory
enable query rewrite as
--可以查詢重寫
select product, country, year, week, inventory, sale, receipts
from sales_fact
model return updated rows
partition by(product, country)
dimension by(year, week)
measures(0 inventory, sale, receipts)
rules automatic order
(inventory [ year, week ] order by year,week asc
= nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]
) ;
檢視查詢:
select * from (select product, country, year, week, inventory, sale, receipts
from sales_fact
model return updated rows
partition by(product, country)
dimension by(year, week)
measures(0 inventory, sale, receipts)
rules automatic order
(inventory [ year, week ] order by year,week asc
= nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]
)
)
where country = 'Australia'
and product = 'Xtend Memory';
可以看到sql訪問的是剛剛建立的物化檢視,而不是sales_fact表,這樣重寫提高了sql語句的效能,因為物化檢視
對規則進行了預求解並存儲了結果
注意:包含model子句的物化檢視不適用快速增量重新整理
model 子句與oracle的並行執行能力實現無縫結合,並行和基於model的sql語句可以改善
分割槽表的查詢效能。
三、並行
select /*+parallel(sf,4)*/product, country, year, week, inventory, sale, receipts
from sales_fact sf
where country = 'Australia'
and product = 'Xtend Memory'
model return updated rows
partition by(product, country)
dimension by(year, week)
measures(0 inventory, sale, receipts)
rules automatic order
( inventory [ year, week ] order by year,week asc
= nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]
);
執行計劃中可以看到 優化器分配了兩組並行執行機來執行所列出的語句
第一組進行表讀取,第二組進行model規則求解。
四、分割槽
重建表並按時create table SALES_FACT
(
country VARCHAR2(40) not null,
region VARCHAR2(30) not null,
product VARCHAR2(50) not null,
year NUMBER(4) not null,
week NUMBER(2) not null,
sale NUMBER,
receipts NUMBER
)
PARTITION BY LIST (year)
(
PARTITION SALES_FACT_PART_1998 VALUES (1998) ,
PARTITION SALES_FACT_PART_1999 VALUES (1999) ,
PARTITION SALES_FACT_PART_2000 VALUES (2000) ,
PARTITION SALES_FACT_PART_2001 VALUES (2001)
);分割槽
select * from (select year, product, country , week, inventory, sale, receipts
from SALES_FACT
where country = 'Australia'
and product = 'Xtend Memory'
model return updated rows
partition by(year, country)
--這裡分割槽只能把year 加上
--維度列 不能再是year,不然會報列重複錯誤
dimension by(product, week)
measures(0 inventory, sale, receipts)
rules automatic order
( inventory [ product, week ] order by product,week asc
= nvl(inventory [ cv(product), cv(week) - 1 ], 0) - sale [ cv(product), cv(week) ] + receipts [ cv(product), cv(week) ]
))
where country = 'Australia'
and product = 'Xtend Memory'
and year=2000;
;
看到分割槽裁剪使得只分文分割槽3 Pstart 3 Pstop 3表示處理的分割槽範圍開始和結束都是id=3的單個分割槽, 這是由model子句
作為分割槽列並且指定了year=2000謂語。還能看到的是執行計劃中的謂詞並沒有year:=2000
select * from (select year, product, country , week, inventory, sale, receipts
from SALES_FACT
where country = ‘Australia’
and product = ‘Xtend Memory’
model return updated rows
partition by(product, country)
dimension by(year, week)
measures(0 inventory, sale, receipts)
rules automatic order
( inventory [ year, week ] order by year,week asc
= nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]
))
where year=2000 and country = ‘Australia’
and product = ‘Xtend Memory’ ;
可以看到執行計劃掃描分割槽範圍是從1到4 等於是全表掃描,並且再最後一步中再進行謂詞year=2000的篩選
year 是維度列,並沒有推進到最開始的表掃描中,雖然year是表sales_fact的分割槽鍵,但他沒有推進檢視中,就不能進行分割槽裁剪
只能進行全表掃描。
當然也可以指定訪問的分割槽
select * from (select year, product, country , week, inventory, sale, receipts
from SALES_FACT partition (SALES_FACT_PART_2000)
--指定訪問year=2000的分割槽
where country = 'Australia'
and product = 'Xtend Memory'
model return updated rows
partition by(product, country)
dimension by(year, week)
measures(0 inventory, sale, receipts)
rules automatic order
( inventory [ year, week ] order by year,week asc
= nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]
))
where year=2000 and country = 'Australia'
and product = 'Xtend Memory' ;
可以看到訪問的分割槽範圍只是id=3這個分割槽,但不同的是year因為是維度列,還是不能推進檢視中。