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