I can reproduce the behavior in my 11.1.0.7 database. I'm not sure I have an explanation, but I have a theory.
If you move the Extend call out of the loop and just add 200 items to the collection, the performance degradation disappears (see below). This makes me believe that this is not only a call to an object method call, but also interaction with an inefficient extension of the collection by 1 element 200 times, and not 200 elements 1 time.
SQL> ed Wrote file afiedt.buf 1 Declare 2 v_test_type test_type := New test_type( New t_tab() ); 3 Procedure run_test As 4 start_time NUMBER := dbms_utility.get_time; 5 Begin 6 v_test_Type.tab.Extend(200); 7 For i In 1 .. 200 Loop 8 v_test_Type.tab(v_test_Type.tab.Last) := Lpad(' ', 10000); 9 v_test_Type.dummy(); --
Here, but perhaps there is some optimization that the compiler can do for calls to expand the collection, which it cannot (or does not) if the procedure call can change the collection.
As a quick test of this speculation, I created a member function, not a member procedure, and named the function in a loop. Since functions do not change the state of an object, they do not exclude the optimization possibilities that I have been thinking about. Of course, if I create an object type using a member function, performance degradation disappears
SQL> ed Wrote file afiedt.buf 1 Create or replace Type test_type As Object( 2 tab t_tab, 3 Member Procedure dummy, 4 Member Function dummy2 return number 5* ); SQL> / Type created. SQL> ed Wrote file afiedt.buf 1 Create or replace Type Body test_type As 2 Member Procedure dummy As Begin 3 Null; --
In the end, it seems to me that Extend is the problematic expression, but the optimizer is smart enough to avoid a penalty if nothing in the loop can change the object.
source share