Oracle PLSQL:使用 TABLE 函数时出现性能问题
Oracle PLSQL: Performance issue when using TABLE functions
我目前在使用 table 函数时遇到性能问题。我会解释的。
我正在使用 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)
);
然后我有一个 table 这种类型的像:
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() 函数是否可能造成如此大的延迟,而内部只有一条记录?我想知道是否有人可以给我一些建议,告诉我我的方法有什么问题,以及是否有其他方法可以实现...
谢谢!!
此问题可能是由于优化程序对 TABLE
函数编辑的 return 行数的估计不佳造成的。 CARDINALITY
或 DYNAMIC_SAMPLING
提示可能是解决问题的最佳方法。
基数估计
Oracle 收集有关 table 和索引的统计信息,以估计访问这些对象的成本。最重要的估计是一个对象将 return 编辑多少行。默认情况下,过程代码没有统计信息,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
提示
正如现在建议的那样,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
提示
更 "official" 的解决方案是使用 DYNAMIC_SAMPLING
提示。此提示告诉 Oracle 在构建解释计划之前在 运行 时间对一些数据进行采样。这会增加一些构建解释计划的成本,但它会 return 真实的行数。如果您事先不知道数字,这可能会更好。
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 |
--------------------------------------------------------------
但是真正慢的是什么?
我们不知道您的查询到底有多慢。但每当事情进展缓慢时,通常最好关注最差的基数估计。行估计从来都不是完美的,但偏离几个数量级会对执行计划产生巨大影响。在最简单的情况下,它可能会将索引范围扫描更改为完整 table 扫描。
我目前在使用 table 函数时遇到性能问题。我会解释的。
我正在使用 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)
);
然后我有一个 table 这种类型的像:
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() 函数是否可能造成如此大的延迟,而内部只有一条记录?我想知道是否有人可以给我一些建议,告诉我我的方法有什么问题,以及是否有其他方法可以实现...
谢谢!!
此问题可能是由于优化程序对 TABLE
函数编辑的 return 行数的估计不佳造成的。 CARDINALITY
或 DYNAMIC_SAMPLING
提示可能是解决问题的最佳方法。
基数估计
Oracle 收集有关 table 和索引的统计信息,以估计访问这些对象的成本。最重要的估计是一个对象将 return 编辑多少行。默认情况下,过程代码没有统计信息,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
提示
正如现在建议的那样,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
提示
更 "official" 的解决方案是使用 DYNAMIC_SAMPLING
提示。此提示告诉 Oracle 在构建解释计划之前在 运行 时间对一些数据进行采样。这会增加一些构建解释计划的成本,但它会 return 真实的行数。如果您事先不知道数字,这可能会更好。
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 |
--------------------------------------------------------------
但是真正慢的是什么?
我们不知道您的查询到底有多慢。但每当事情进展缓慢时,通常最好关注最差的基数估计。行估计从来都不是完美的,但偏离几个数量级会对执行计划产生巨大影响。在最简单的情况下,它可能会将索引范围扫描更改为完整 table 扫描。