我试图在对象上使用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
替换为具有相同列定义的实际表,则可以显着提高函数的性能。
答案 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”没有提示,结果是计划的变化。检查解释计划与真实表格与集合与暗示集合的比较,并且有助于使用合理的基数提示编号,您的计划和绩效应该得到改善。