1. 案例起因公司門店應用程式每天都要出乙份報表,用來統計所有商品當天的期初庫存數量、入庫數量、出庫數量
及當天的期末庫存數量。執行半年以後,這份報表執行越來越慢,到現在,每次執行該報表顯示當天資料時需要近20秒的時間。於是開發人員找到我,希望我看看,是不是可以使該報表執行的時間更短。
該報表就是一段sql語句,主要由三部分組成,第一部分是計算每個商品的期初數量,第二部分是計算每個商品的當天發生(包括入庫和出庫的)數量,第三部分是計算每個商品的期末數量,也就是當天的餘額。每個部分使用union all連線起來。
我看到該報表,第乙個感覺就是這段sql裡的每個部分都要對錶進行掃瞄,明顯成本過高。應該可以使用with as進行改寫。
2. with as的含義
with as短語,也叫做子查詢部分(subquery factoring),可以讓你做很多事情,定義乙個sql片斷,該sql片斷會被整個sql語句所用到。有的時候,是為了讓sql語句的可讀性更高些,也有可能是在union all的不同部分,作為提供資料的部分。
特別對於union all比較有用。因為union all的每個部分可能相同,但是如果每個部分都去執行一遍的話,則成本太高,所以可以使用with as短語,則只要執行一遍即可。如果with as短語所定義的表名被呼叫兩次以上,則優化器會自動將with as短語所獲取的資料放入乙個temp表裡,如果只是被呼叫一次,則不會。而提示materialize則是強制將with as短語裡的資料放入乙個全域性臨時表裡。很多查詢通過這種方法都可以提高速度。
3. 案例說明
首先介紹該sql所涉及到的主要的表的結構。該表表名為fin,用來存放每天每個商品的發生數以及該商
品的餘額數。其表結構為如下所示(這裡我只選取了與我們要討論的sql相關的部分表字段)。
sql> desc fin
名稱 是否為空? 型別
day date
sku varchar2(8)
inqty number(16,6)
outqty number(16,6)
lastqty number(16,6)
簡單解釋一下各個欄位的含義:
1) day:發生的日期。
2) sku:發生交易的商品**。
3) inqty:商品入庫數量。
4) outqty:商品出庫數量。
5) lastqty:商品的餘額數量。
該表中含有的記錄數量為:
sql> select count(*) from fin;
count(*)
select
sku,
sum(initqty) as initqty,
sum(inqty) as inqty,sum(outqty) as outqty,
sum(lastqty) as lastqty
from (
select sku,lastqty as initqty,0 as inqty,0 as outqty,0 as lastqty
from fin
where day=to_date('20030713','yyyymmdd')
union all
select sku,0 as initqty,inqty,outqty,0 as lastqty
from fin
where day>=to_date('20030714','yyyymmdd') and day<=to_date('20030714','yyyymmdd')
union all
select sku,0 as initqty,0 as inqty,0 as outqty,lastqty
from fin
where day=to_date('20030714','yyyymmdd')
group by sku;
我們來看該sql所花費的時間為:
sql> set timing on
sql> /
sku initqty inqty outqty lastqty
00106162 0 0 12 60
00106467 0 20 10 60
已選擇956行。
然後,我們來對該sql進行改寫一番,如下所示:
with result as (
select /*+ materialize */ day,sku,inqty,outqty,lastqty
from fin
where day>=to_date('20030713','yyyymmdd') and day<=to_date('20030714','yyyymmdd'))
select
sku,
sum(initqty) as initqty,
sum(inqty) as inqty,
sum(outqty) as outqty,
sum(lastqty) as lastqty
from (
select sku,lastqty as initqty,0 as inqty,0 as outqty,0 as lastqty
from result
where day=to_date('20030713','yyyymmdd')
union all
select sku,0 as initqty,inqty,outqty,0 as lastqty
from result
where day=to_date('20030714','yyyymmdd')
union all
select sku,0 as initqty,0 as inqty,0 as outqty,lastqty
from result
where day=to_date('20030714','yyyymmdd')
group by sku;
我們來看修改後的sql所花費的時間為:
sql> set timing on
sql> /
sku initqty inqty outqty lastqty
00106162 0 0 12 60
00106467 0 20 10 60
已選擇956行。
從這裡可以看到,通過with as可以從20秒降低到6秒,幾乎提高了65%的效能。
SQL中使用WITH AS提高效能
本文內容一部分來自 一 with as的含義 with as短語,也叫做子查詢部分 subquery factoring 可以讓你做很多事情,定義乙個sql片斷,該sql片斷會被整個sql語句所用到。有的時候,是為了讓sql語句的可讀性更高些,也有可能是在union all的不同部分,作為提供資料的...
SQL 中使用 WITH AS 提高效能
一 with as的含義 with as短語,也叫做子查詢部分 subquery factoring 可以讓你做很多事情,定義乙個sql片斷,該sql片斷會被整個sql語句所用到。有的時候,是為了讓sql語句的可讀性更高些,也有可能是在union all的不同部分,作為提供資料的部分。特別對於uni...
使用WITH AS提高效能簡化巢狀SQL
特別對於union all比較有用。因為union all的每個部分可能相同,但是如果每個部分都去執行一遍的話,則成本太高,所以可以使用with as短語,則只要執行一遍即可。如果with as短語所定義的表名被呼叫兩次以上,則優化器會自動將 with as短語所獲取的資料放入乙個temp表裡,如果...