使用table()函数加速更慢

时间:2012-11-28 21:18:30

标签: sql oracle plsql

我试图在对象上使用table()函数,以便在PL / SQL函数中进行连接。使用此功能时,查询最多可能需要20分钟才能完成;当我直接将数据输入表中时,它只需不到5秒。我一直无法弄清楚为什么会有这么大的差异,但我最好的预感是没有使用连接表中列的索引。表和对象的列定义是相同的。

以下是一些示例代码:

create or replace type VARCHAR20_TYPE is OBJECT
(
  val varchar2(20 byte);
);

create or replace type VARCHAR20_TABLE is table of VARCHAR20_TYPE;


create or replace FUNCTION test_function( 
    in_project_ids VARCHAR20_TABLE
  ) RETURN INTEGER
  IS
    l_result INTEGER;
  BEGIN

    SELECT count(*) into l_result FROM project p JOIN TABLE(in_project_ids) t ON p.project_id = t.val;      
    RETURN l_result;

  END;

如果我要将上面示例中的in_project_ids替换为具有相同列定义的实际表,则可以显着提高函数的性能。

1 个答案:

答案 0 :(得分:4)

这是可以预料的。当处理像这样的内存数组时,Oracle将假设该表中将有8k行。

试试这个来帮助它:

SELECT /*+ cardinality(t, 20) */ count(*) into l_result FROM project p JOIN TABLE(in_project_ids) t ON p.project_id = t.val;

其中20应该是对实际条目数的粗略猜测。这是提示“ok”(并且需要帮助优化器)的边缘情况之一。

修改

例如:

SQL> explain plan for SELECT /*+ cardinality(t, 1) */ * FROM project p JOIN TABLE(VARCHAR20_TABLE()) t ON p.project_id = t.val;

Explained.

SQL> select * From table(dbms_xplan.display);

Plan hash value: 858605789

--------------------------------------------------------------------------------------------------------
| Id  | Operation                               | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                        |              |     1 |    27 |    30   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                           |              |       |       |            |          |
|   2 |   NESTED LOOPS                          |              |     1 |    27 |    30   (0)| 00:00:01 |
|   3 |    COLLECTION ITERATOR CONSTRUCTOR FETCH|              |     1 |     2 |    29   (0)| 00:00:01 |
|*  4 |    INDEX UNIQUE SCAN                    | SYS_C0011177 |     1 |       |     0   (0)| 00:00:01 |
|   5 |   TABLE ACCESS BY INDEX ROWID           | PROJECT      |     1 |    25 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------


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

   4 - access("P"."PROJECT_ID"=TO_NUMBER(SYS_OP_ATG(VALUE(KOKBF$),1,2,2)))

Note
-----
   - dynamic sampling used for this statement (level=2)

21 rows selected.

SQL> explain plan for SELECT * FROM project p JOIN TABLE(VARCHAR20_TABLE()) t ON p.project_id = t.val;

Explained.

SQL> select * From table(dbms_xplan.display);

Plan hash value: 583089723

--------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |         |  8168 |   215K|    33   (4)| 00:00:01 |
|*  1 |  HASH JOIN                             |         |  8168 |   215K|    33   (4)| 00:00:01 |
|   2 |   TABLE ACCESS FULL                    | PROJECT |  2000 | 50000 |     3   (0)| 00:00:01 |
|   3 |   COLLECTION ITERATOR CONSTRUCTOR FETCH|         |  8168 | 16336 |    29   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------

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


   1 - access("P"."PROJECT_ID"=TO_NUMBER(SYS_OP_ATG(VALUE(KOKBF$),1,2,2)))

Note
-----
   - dynamic sampling used for this statement (level=2)

19 rows selected.

一个简单的例子,但是注意集合fetch = 8168上的“Rows”没有提示,结果是计划的变化。检查解释计划与真实表格与集合与暗示集合的比较,并且有助于使用合理的基数提示编号,您的计划和绩效应该得到改善。