2012-07-20 30 views
1

的速度,我有兩個疑問:「提取物(從SYSDATE年)」

with tmp as (
select asy.aim_student_id, ast.aim_test, asq.response 
    from aim_student_test ast 
    join aim_student_qst asq on (asq.aps_yr = ast.aps_yr and asq.aim_test = ast.aim_test and asq.aim_id = ast.aim_id) 
    join aim_student_yr asy on (asy.aps_yr = ast.aps_yr and asy.aim_student_yr_id = ast.aim_student_yr_id) 
    where asq.aps_yr = '2012' 
    and asq.qst_num = 1) 
select aim_student_id, aim_test, response 
    from tmp 
    where response is null 
    -- execution-time: 0.032 seconds 


define this_year = extract(year from sysdate) 
with tmp as (
select asy.aim_student_id, ast.aim_test, asq.response 
    from aim_student_test ast 
    join aim_student_qst asq on (asq.aps_yr = ast.aps_yr and asq.aim_test = ast.aim_test and asq.aim_id = ast.aim_id) 
    join aim_student_yr asy on (asy.aps_yr = ast.aps_yr and asy.aim_student_yr_id = ast.aim_student_yr_id) 
    where asq.aps_yr = &this_year 
    and asq.qst_num = 1) 
select aim_student_id, aim_test, response 
    from tmp 
    where response is null 
    -- execution-time: 82.202 seconds 

唯一的區別是,在一個我用「2012」,另一個我實現了提取物(一年SYSDATE)。

我只能想象Oracle正在計算它檢查的每條記錄的提取(年份來自sysdate),而且我無法弄清楚如何使它計算一次並將其用作變量。搜索沒有給我回答我尋找的答案...所以我來找SO.com的魔術師。如何正確使用

extract(year from sysdate) 

作爲變量?

回答

2

使用查詢&this_year導致extract(year from sysdate)的替代,所以第二個查詢實際上有:

where asq.aps_yr = extract(year from sysdate) 

您可以從第二個解釋計劃看。這本身可能不是問題;可能放緩的是,這樣做是將計劃從index range scan更改爲index skip scan而不是aim_student_qstp1。真正的區別是,在你比較asq.aps_yr爲一個字符串('2012')快速版本,在第二個它是一個數字(2012),以及 - 在解釋計劃也表明 - 這是導致它做to_number(asq.aps_yr)這是停止正在使用的索引。如果您想查詢運行前一次計算,然後把它作爲一個變量,至少有兩種方式(在SQL

where asq.aps_yr = to_char(&this_year) 

你可以在你的代碼通過使得解決這個問題* Plus/SQL Developer)。與替代變量堅持你可以使用column命令,而不是define

column tmp_this_year new_value this_year 
set termout off 
select extract(year from sysdate) as tmp_this_year from dual; 
set termout on 
set verify off 

...這使得&this_year=2012(在termout改變只是使實際的檢索無形的,以及verify停止它告訴你,當它使用替代;既有這樣你就不會得到你的腳本額外產出),以及改變你的查詢有:

where asq.aps_yr = '&this_year' 

...這樣的值被視爲一個字符串,使得to_char()不必要的。

或者你可以使用綁定變量:

var this_year varchar2(4); 
set feedback off; 
exec :this_year := extract(year from sysdate); 

...然後你的查詢有:

where asq.aps_yr = :this_year 

注意,在這種情況下,你不需要引號是因爲綁定變量被定義爲一個字符串 - 在exec中有一個隱式轉換來設置它。

+0

嘿夥伴 - 對不起,我沒有更早發佈 - 我兼職工作。今天是我本週回來的第一天,這是我第一次嘗試。它的工作方式非常魅力,完全符合我的要求 - 因此我將其標記爲我接受的答案,因爲另一個很有幫助,但並未完全涵蓋我所尋找的內容。 – nebffa 2012-07-23 23:17:49

+0

@AlexPoole。 。 。非常好的解釋! – 2012-07-24 14:50:56

2

我懷疑的差異是由於從提取日起一年。我很確定甲骨文只會提取一年,因爲它在第二種情況下使用變量。

的差異是由於通過查詢所使用的執行路徑。您需要發佈執行計劃才能真正發現差異。使用顯式常量可爲優化程序提供有關選擇最佳查詢計劃的更多信息。

例如,如果該數據是由年分區,然後以恆定的年,Oracle可以確定哪個分區具有數據。在第二種情況下,Oracle可能無法將該值識別爲常量,並且需要讀取所有數據分區。這只是可能發生的一個例子 - 我不確定Oracle在這種情況下會做什麼。

+0

哇,檢查計劃是有趣的,雖然它還沒有解決我的問題,但它正是我試圖學習的東西(長期有用的工具)的類型。謝謝。 [快速計劃](http://img833.imageshack.us/img833/4052/fastplan.png)和[慢速計劃](http://img687.imageshack.us/img687/3623/slowplan.png) 您是對的,顯然兩者之間存在巨大差異。現在我的問題是......我如何從這裏解決問題? – nebffa 2012-07-20 02:10:19

+0

我想我正在尋找的是如何將提取(從sysdate中提取)作爲CONSTANT提供給Oracle。在開始優化其查詢之前。 我們可以使用'2012',但是這個查詢和我正在創建的許多其他數據將在這裏使用數年。我在今年年底完成了這項工作,如果我可以創建這些查詢以便始終工作而無需創建額外的工作 - 那將非常棒。另外,學習非常有趣 – nebffa 2012-07-20 02:16:02

+0

請問另一個問題,包括查詢計劃,表結構和大小。你有一個關於性能的非常具體的問題,但是你問了一個非常普遍的問題。 – 2012-07-20 02:22:41