使用表函数时,我目前遇到性能问题。我会解释一下。
我正在使用Oracle类型,其中一个定义如下:
create or replace TYPE TYPESTRUCTURE AS OBJECT
(
ATTR1 VARCHAR2(30),
ATTR2 VARCHAR2(20),
ATTR3 VARCHAR2(20),
ATTR4 VARCHAR2(20),
ATTR5 VARCHAR2(20),
ATTR6 VARCHAR2(20),
ATTR7 VARCHAR2(20),
ATTR8 VARCHAR2(20),
ATTR9 VARCHAR2(20),
ATTR10 VARCHAR2(20),
ATTR11 VARCHAR2(20),
ATTR12 VARCHAR2(20),
ATTR13 VARCHAR2(10),
ATTR14 VARCHAR2(50),
ATTR15 VARCHAR2(13)
);
然后我有一个这种类型的表,如:
create or replace TYPE TYPESTRUCTURE_ARRAY AS TABLE OF TYPESTRUCTURE ;
我有一个带有以下变量的程序:
arr QCSTRUCTURE_ARRAY;
arr2 QCSTRUCTURE_ARRAY;
ARR只包含一个TYPESTRUCTURE实例,其所有属性都设置为NULL,但ATTR4设置为'ABC'
ARR2完全是空的。
这是给我性能问题的部分。
目的是从视图中取一些值(取决于ATTR4上的值)并填充相同或相似结构的值。所以我做了以下几点:
SELECT TYPESTRUCTURE(MV.A,null,null,MV.B,MV.C,MV.D,null,null,MV.E,null,null,MV.F,MV.F,MV.G,MV.H)
BULK COLLECT INTO arr2
FROM TABLE(arr) PARS
JOIN MYVIEW MV
ON MV.B = PARS.ATTR4;
此处的代码正常工作,但执行查询需要15秒的事实......
此查询将在大约20个TYPESTRUCTURE(或行)实例中填入ARR。
看起来视图上可能有很多数据。但让我感到奇怪的是,如果我更改了查询并设置了类似于下面的硬编码,则完全快速(毫秒)
SELECT TYPESTRUCTURE(MV.A,null,null,MV.B,MV.C,MV.D,null,null,MV.E,null,null,MV.F,MV.F,MV.G,MV.H)
BULK COLLECT INTO arr2
FROM (SELECT 'ABC' ATTR4 FROM DUAL) PARS
JOIN MYVIEW MV
ON MV.B = PARS.ATTR4;
在这个新查询中,我直接对值进行硬编码,但保留连接以尝试测试与上面的相似但没有TABLE()函数的内容。
所以这里我的问题....这个TABLE()函数是否有可能创建如此大的延迟,内部只有一条记录?我想知道是否有人可以就我的方法中的错误给出一些建议,以及是否可能有其他方法来实现...
谢谢!
答案 0 :(得分:0)
此问题可能是由优化程序对TABLE
函数返回的行数估计不佳引起的。 CARDINALITY
或DYNAMIC_SAMPLING
提示可能是解决问题的最佳方式。
基数估算
Oracle收集有关表和索引的统计信息,以估算访问这些对象的成本。最重要的估计是对象将返回多少行。默认情况下,过程代码没有统计信息,Oracle不会尝试解析代码并估计将生成多少行。每当Oracle看到一个过程行源时,它就会使用一个静态数字。在我的数据库中,数字是16360.在大多数数据库中,估计值是8192,正如beherenow指出的那样。
explain plan for
select * from table(sys.odcinumberlist(1,2,3));
select * from table(dbms_xplan.display(format => 'basic +rows'));
Plan hash value: 2234210431
--------------------------------------------------------------
| Id | Operation | Name | Rows |
--------------------------------------------------------------
| 0 | SELECT STATEMENT | | 16360 |
| 1 | COLLECTION ITERATOR CONSTRUCTOR FETCH| | 16360 |
--------------------------------------------------------------
修复#1:CARDINALITY
提示
正如beherenow建议的那样,CARDINALITY
提示可以通过静态告知Oracle要估算多少行来解决这个问题。
explain plan for
select /*+ cardinality(1) */ * from table(sys.odcinumberlist(1,2,3));
select * from table(dbms_xplan.display(format => 'basic +rows'));
Plan hash value: 2234210431
--------------------------------------------------------------
| Id | Operation | Name | Rows |
--------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
| 1 | COLLECTION ITERATOR CONSTRUCTOR FETCH| | 16360 |
--------------------------------------------------------------
修复#2:DYNAMIC_SAMPLING
提示
更“官方”的解决方案是使用DYNAMIC_SAMPLING
提示。此提示告诉Oracle在构建解释计划之前在运行时对一些数据进行采样。这会增加构建解释计划的成本,但会返回真正的行数。如果您不提前知道这个数字,这可能会更好。
explain plan for
select /*+ dynamic_sampling(2) */ * from table(sys.odcinumberlist(1,2,3));
select * from table(dbms_xplan.display(format => 'basic +rows'));
Plan hash value: 2234210431
--------------------------------------------------------------
| Id | Operation | Name | Rows |
--------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 |
| 1 | COLLECTION ITERATOR CONSTRUCTOR FETCH| | 3 |
--------------------------------------------------------------
但是什么真的很慢?
我们不知道您的查询确实很慢。但是每当事情变得缓慢时,通常最好关注最差的基数估计。行估计从来都不是完美的,但是关闭几个数量级会对执行计划产生巨大影响。在最简单的情况下,它可能会将索引范围扫描更改为全表扫描。