2009-04-23 37 views
1

我在用於遊標的Oracle select語句時出現性能問題。在聲明中,SELECT子句中的其中一個條款評估起來很昂貴(這是一個PL/SQL過程調用,它非常大量地訪問數據庫)。但是,WHERE子句和ORDER BY子句很直接。我希望Oracle首先執行WHERE子句來識別與查詢匹配的記錄集合,然後執行ORDER BY子句對它們進行排序,最後評估SELECT子句中的每個術語。當我在一個遊標中使用這個語句並從中抽取結果時,我期望只有在需要從遊標請求每個結果時,纔會根據需要執行昂貴的術語評估。在SQL查詢的SELECT子句中對Oracle PL/SQL語句的惰性評估

但是,我發現這不是Oracle使用的順序。相反,它似乎在執行排序之前對每個匹配WHERE子句的記錄在SELECT子句中進行評估。因此,在從遊標返回任何結果之前,調用結果集中的每個結果結果都會調用花費昂貴的過程。

我希望能夠儘快從光標中獲得第一個結果。任何人都可以告訴我如何說服Oracle在執行排序之前不要評估SELECT語句中的過程調用嗎?

這一切都是可能更容易在示例代碼來描述:

給定一個表examplecabd,我有這樣一種說法:

select a, b, expensive_procedure(c) 
    from example 
where <the_where_clause> 
order by d; 

在執行此,對於與WHERE子句匹配的每條記錄,都會調用expensive_procedure(),即使我將該語句作爲遊標打開並僅從其中獲取一個結果。

我已經嘗試重組而作的陳述:

select a, b, expensive_procedure(c) 
    from example, (select example2.rowid, ROWNUM 
        from example example2 
        where <the_where_clause> 
        order by d) 
    where example.rowid = example2.rowid; 

ROWNUM在內SELECT聲明力量甲骨文存在先對其進行評估。這種重組具有理想的性能優勢。不幸的是,它並不總是尊重所需的順序。

爲了清楚起見,我知道我不會改進返回整個結果集所需的時間。我期待着改善回覆聲明中前幾項結果的時間。我希望在迭代遊標結果時花費的時間是漸進式的,而不是在返回第一個結果之前全部結束。

任何Oracle大師能告訴我如何說服Oracle停止執行PL/SQL,直到它有必要嗎?

+0

您是否嘗試了FIRST_ROWS(1)提示? – 2011-06-29 02:20:29

回答

2

爲什麼在在線視圖加入實例本身?爲什麼不乾脆:

select /*+ no_merge(v) */ a, b, expensive_procedure(c) 
from 
(select a, b, c 
    from example 
    where <the_where_clause> 
    order by d 
) v; 
0

你可能想試試這個

select a, b, expensive_procedure(c) 
    from example, (select /*+ NO_MERGE */ 
        example2.rowid, 
        ROWNUM 
        from example example2 
        where <the_where_clause> 
        order by d) 
    where example.rowid = example2.rowid; 
0

恐怕有人形式這項工作的?

FOR R IN (SELECT a,b,c FROM example WHERE ...) LOOP 
    e := expensive_procedure(R.c); 
    ... 
END LOOP; 
1

這是做你打算的嗎?

WITH 
cheap AS 
(
    SELECT A, B, C 
    FROM EXAMPLE 
    WHERE <the_where_clause> 
) 
SELECT A, B, expensive_procedure(C) 
FROM cheap 
ORDER BY D 
0

如果您WHERE條件是平等的,我。即

WHERE col1 = :value1 
     AND col2 = :value2 

你可以(col1, col2, d)創建複合指數:

CREATE INDEX ix_example_col1_col2_d ON example(col1, col2, d) 

,並提示您的查詢使用它:

SELECT /*+ INDEX (e ix_example_col1_col2_d) */ 
     a, b, expensive_procedure(c) 
FROM example e 
WHERE col1 = :value1 
     AND col2 = :value2 
ORDER BY 
     d 

在下面的例子中,t_even1,000,000行表value上的索引。

擷取100列從該查詢:

SELECT SYS_GUID() 
FROM t_even 
ORDER BY 
     value 

是即時的(0,03秒),而此一:

SELECT SYS_GUID() 
FROM t_even 
ORDER BY 
     value + 1 

約需170秒抓取第一100行。

SYS_GUID()Oracle

相當昂貴的提議人,你也可以使用這個:

SELECT a, b, expensive_proc(c) 
FROM (
     SELECT /*+ NO_MERGE */ 
       * 
     FROM mytable 
     ORDER BY 
       d 
     ) 

,但使用索引將提高查詢的響應時間(第一行是多久回)。

0

我們嘗試過的解決方案的關鍵問題之一是如何調整生成SQL以正確構建查詢的應用程序。構建的SQL將根據檢索的列數,where子句中的條件數量和類型以及順序中的表達式的數量和類型而有所不同。

返回ROWIDs以加入外部的內聯視圖是我們可以使用的幾乎完全通用的解決方案,除非搜索返回大部分數據。在這種情況下,優化器[正確]決定HASH連接比NESTED LOOP便宜。

另一個問題是涉及的一些對象是不能有ROWID的VIEW。

有關信息:「D」不是拼寫錯誤。 order by的表達式不被選爲返回值的一部分。不是一件不尋常的事:

select index_name, column_name 
from user_ind_columns 
where table_name = 'TABLE_OF_INTEREST' 
order by index_name, column_position; 

在這裏,你不需要知道column_position,但排序是至關重要的。

我們有理由避免在解決方案中需要提示,但看起來並不是這樣。

感謝您的建議,迄今爲止 - 我們已經嘗試了其中大部分已經......