大型对象类型的奇怪行为
我认识到,当实例变大时,调用 Oracle 对象类型的方法需要更长的时间。
下面的代码只是将行添加到存储在对象类型中的集合中,并在循环中调用 empty dummy
过程。
当集合中的行数越多时,调用所花费的时间就越长。当我删除对 dummy
的调用时,性能好多了(集合仍然包含相同数量的记录):
Calling dummy: Not calling dummy:
11 0
81 0
158 0
要重现的代码:
Create Type t_tab Is Table Of VARCHAR2(10000);
Create Type test_type As Object(
tab t_tab,
Member Procedure dummy
);
Create Type Body test_type As
Member Procedure dummy As Begin
Null; --# Do nothing
End dummy;
End;
Declare
v_test_type test_type := New test_type( New t_tab() );
Procedure run_test As
start_time NUMBER := dbms_utility.get_time;
Begin
For i In 1 .. 200 Loop
v_test_Type.tab.Extend;
v_test_Type.tab(v_test_Type.tab.Last) := Lpad(' ', 10000);
v_test_Type.dummy(); --# Removed this line in second test
End Loop;
dbms_output.put_line( dbms_utility.get_time - start_time );
End run_test;
Begin
run_test;
run_test;
run_test;
End;
我尝试了两者 10 克 和 11 克。
谁能解释/重现这种行为?
I recognized that calling a method on an Oracle Object Type takes longer when the instance gets bigger.
The code below just adds rows to a collection stored in the Object Type and calls the empty dummy
-procedure in the loop.
Calls are taking longer when more rows are in the collection. When I just remove the call to dummy
, performance is much better (the collection still contains the same number of records):
Calling dummy: Not calling dummy:
11 0
81 0
158 0
Code to reproduce:
Create Type t_tab Is Table Of VARCHAR2(10000);
Create Type test_type As Object(
tab t_tab,
Member Procedure dummy
);
Create Type Body test_type As
Member Procedure dummy As Begin
Null; --# Do nothing
End dummy;
End;
Declare
v_test_type test_type := New test_type( New t_tab() );
Procedure run_test As
start_time NUMBER := dbms_utility.get_time;
Begin
For i In 1 .. 200 Loop
v_test_Type.tab.Extend;
v_test_Type.tab(v_test_Type.tab.Last) := Lpad(' ', 10000);
v_test_Type.dummy(); --# Removed this line in second test
End Loop;
dbms_output.put_line( dbms_utility.get_time - start_time );
End run_test;
Begin
run_test;
run_test;
run_test;
End;
I tried with both 10g and 11g.
Can anyone explain/reproduce this behavior?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我可以在 11.1.0.7 数据库上重现该行为。我不确定我有一个解释,但我确实有一个理论。
如果将 Extend 调用移出循环并仅向集合添加 200 个元素,性能的下降就会消失(见下文)。这让我相信,问题不仅仅在于调用对象方法的行为——似乎与集合 1 个元素 200 次而不是 200 个元素 1 次的低效扩展存在某种交互。
此处推测,但如果对过程的调用可能会修改集合,则编译器可能能够对扩展集合的调用进行一些优化,而编译器无法(或不会)进行这些优化。
作为对该推测的快速测试,我创建了一个成员函数而不是成员过程,并在循环中调用该函数。由于函数不会修改对象状态,因此它们不会排除我推测的那种优化。果然,如果我用成员函数创建对象类型,性能下降就会消失。
最后,在我看来,有问题的语句是 Extend,但优化器足够聪明,能够避免惩罚。在循环中能够修改对象。
I can reproduce the behavior on my 11.1.0.7 database. I'm not certain that I have an explanation, but I do have a theory.
If you move the Extend call outside the loop and just add 200 elements to the collection, the decrease in performance disappears (see below). That leads me to believe that it is not solely the act of calling the object method that is the problem-- there appears to be some interaction with the inefficient extension of the collection by 1 element 200 times rather than by 200 elements 1 time.
Speculating here, but perhaps there is some optimization that the compiler is able to make to the calls to extend the collection that it cannot (or does not) make if a call to a procedure might modify the collection.
As a quick test of that speculation, I created a member function rather than a member procedure and called the function in the loop. Since functions don't modify object state, they wouldn't preclude the sort of optimizations I was speculating about. Sure enough, if I create the object type with a member function, the decline in performance disappears
In the end, it looks to me like the problematic statement is the Extend but that the optimizer is smart enough to be able to avoid the penalty if nothing in the loop is able to modify the object.
我自己发现了,问题在 使用中进行了描述SELF IN OUT NOCOPY 会员程序:
因此,每次过程调用时,我的整个对象都会被复制两次,并且随着大小的增加,这需要越来越长的时间。
解决方案是使用
SELF IN OUT NOCOPY test_type
作为我的过程声明的第一个参数:并且仍然在没有参数的情况下调用
性能恢复正常:
Found out myself, the problem is described in Using SELF IN OUT NOCOPY with Member Procedures:
So with every procedure call my whole object was copied twice, and as size was increasing this took longer and longer.
The solution is to use
SELF IN OUT NOCOPY test_type
as first parameter of my procedure declaration:and is still called without parameter
Performance is back to normal: