2

我的查詢是這樣的:甲骨文分頁查詢和用戶定義的函數 - 執行速度慢

select id, fn_calc(col) 
    from table_a 
    order by id 
    offset 1483800 rows fetch next 100 rows only; 

注意,尋呼偏移量是非常高的 - table_a有150萬左右的行。

上述查詢需要很長時間,但當fn_calc(col)被替換爲col時,查詢速度令人滿意 - 至少快5倍。但是當偏移量爲0或100時,兩個查詢幾乎同樣快。爲什麼這個區別?我能想到的

可能的原因:

  • 甲骨文執行fn_calc() 1483900次,雖然它在邏輯上是不neccessary。 (這足以稱之爲只有100次)
  • 在查詢用戶函數調用的成本是非常高的。

我使用Exadata上的Oracle 12c上。

任何建議可以提供幫助。

UPDATE:

當如下上面的查詢被改變:

select id, fn_calc(col) 
    from 
    (
    select id, col 
    from table_a 
    order by id 
    offset 1483800 rows fetch next 100 rows only 
    ) 
    order by id 

查詢速度是可比的情況下,當fn_calc()不被調用。

這是爲什麼?

UPDATE:

的執行計劃如下:(對不起,目前只有我是SQLDevelper,所以我不得不抓住的結果。)

第一個查詢:

First query

第二個查詢(其使用子查詢):

要降選民和近選民:你投票前,請註明您對這個問題的關注。我會相應地更新我的問題。這個問題是關於我真實和嚴重的問題。請不要剝奪獲得幫助的機會。

+0

兩個檢查執行計劃。可能是索引使用。其次你需要爲每一行調用函數,這也需要時間。 – lad2025

+0

有多少個不同的col值?函數是確定性的嗎?你也沒有定義任何使得OFFSET有效不重要的ORDER BY – Husqvik

+0

@ lad2025執行計劃是相同的。 – zeodtr

回答

0

首先,當您不使用ORDER BY子句時,分頁查詢的用途是什麼。您隨機讀取行,即甲骨文將在內部應用ORDER BY NULL

其次,因爲你必須在過濾謂詞在選擇功能並沒有,說明計劃應該是相同的。花費的唯一的額外時間應是由於功能。

例如,

SQL> CREATE OR REPLACE FUNCTION f_char(
    2  i_empno NUMBER) 
    3 RETURN VARCHAR2 
    4 AS 
    5 v_empno VARCHAR2(10); 
    6 BEGIN 
    7 v_empno := TO_CHAR(i_empno); 
    8 return v_empno; 
    9 END; 
10/

Function created. 

讓我們比較解釋計劃

SQL> set autot on explain 
SQL> 
SQL> SELECT f_char(empno) FROM emp 
    2 OFFSET 5 ROWS 
    3 FETCH NEXT 5 rows only; 

F_CHAR(EMPNO) 
-------------------------------------------------------------------------------- 
7698 
7782 
7788 
7839 
7844 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 3611411408 

------------------------------------------------------------------------------- 
| Id | Operation    | Name | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |  | 14 | 28210 |  4 (0)| 00:00:01 | 
|* 1 | VIEW     |  | 14 | 28210 |  4 (0)| 00:00:01 | 
|* 2 | WINDOW NOSORT STOPKEY|  | 14 | 56 |  4 (0)| 00:00:01 | 
| 3 | TABLE ACCESS FULL | EMP | 14 | 56 |  4 (0)| 00:00:01 | 
------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=CASE WHEN 
       (5>=0) THEN 5 ELSE 0 END +5 AND "from$_subquery$_002"."rowlimit_$$ 
_rownu 

       mber">5) 
    2 - filter(ROW_NUMBER() OVER (ORDER BY NULL)<=CASE WHEN (5>=0) 
       THEN 5 ELSE 0 END +5) 


SQL> SELECT empno FROM emp 
    2 OFFSET 5 ROWS 
    3 FETCH NEXT 5 rows only; 

    EMPNO 
---------- 
     7698 
     7782 
     7788 
     7839 
     7844 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 3611411408 

------------------------------------------------------------------------------- 
| Id | Operation    | Name | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |  | 14 | 364 |  4 (0)| 00:00:01 | 
|* 1 | VIEW     |  | 14 | 364 |  4 (0)| 00:00:01 | 
|* 2 | WINDOW NOSORT STOPKEY|  | 14 | 56 |  4 (0)| 00:00:01 | 
| 3 | TABLE ACCESS FULL | EMP | 14 | 56 |  4 (0)| 00:00:01 | 
------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=CASE WHEN 
       (5>=0) THEN 5 ELSE 0 END +5 AND "from$_subquery$_002"."rowlimit_$$ 
_rownu 

       mber">5) 
    2 - filter(ROW_NUMBER() OVER (ORDER BY NULL)<=CASE WHEN (5>=0) 
       THEN 5 ELSE 0 END +5) 
+0

對不起,我簡化了查詢太多。在真正的查詢當然有一個命令的條款。我已經編輯了相應的問題。 – zeodtr

+0

問題是由該功能引起的額外成本不合理地高。我懷疑可能存在與Oracle在分頁查詢中處理用戶定義函數有關的其他原因。 – zeodtr

+0

請參閱我更新的問題。它變得有趣... – zeodtr