1. 程式人生 > >oracle sql 高階程式設計學習筆記(二十三)

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因為是維度列,還是不能推進檢視中。