Dion Cho – Oracle Performance Storyteller

We are natural born scientists

LOB vs. SQL*Trace

with 2 comments

Have you noticed this abnormality of SQL*Trace on reading LOB?

Here we have 2 tables t1 and t2 which have same volume but with different the data types - LOB vs. VARCHAR2.

create table t1(c1 int, c2 clob);

declare
	v_clob clob := rpad('x', 4000, 'x');
begin
	for idx in 1 .. 1000 loop
		insert into t1 values(idx, v_clob);
	end loop;
end;
/

create table t2(c1 int, c2 varchar2(4000));

declare
	v_varchar varchar2(4000) := rpad('x', 4000, 'x');
begin
	for idx in 1 .. 1000 loop
		insert into t2 values(idx, v_varchar);
	end loop;
end;
/


Reading t1.LOB takes 2 min.

UKJA@ukja102> select * from t1;

        C1                                                                      
----------                                                                      
C2                                                                              
--------------------------------------------------------------------------------
       583                                                                      
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
...

1000 rows selected.

Elapsed: 00:02:05.53
UKJA@ukja102> 



, while reading t2.VARCAR2 takes 10 sec.

UKJA@ukja102> select * from t2;

        C1                                                                      
----------                                                                      
C2                                                                              
--------------------------------------------------------------------------------
         5                                                                      
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
...
1000 rows selected.

Elapsed: 00:00:10.50



The performance difference between LOB and VARCHAR2 is not an issue here. The abnormality is observed in the report by SQL*Trace and tkprof. See following.

select * 
from
 t1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch     1001      0.14       0.09          0       1009          0        1000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total     1003      0.14       0.09          0       1009          0        1000

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 61  

Rows     Row Source Operation
-------  ---------------------------------------------------
   1000  TABLE ACCESS FULL T1 (cr=1009 pr=0 pw=0 time=41472 us)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                    1002        0.00          0.00
  SQL*Net message from client                  1002        0.00          0.13
********************************************************************************



Reading t1.LOB took 2 min, but the tkprof report shows the time of just around 0.1 sec. Where has the actual 2 min gone?

Reading t2.VARCHAR2 shows what I expected. Around 10 sec waiting for the request of the client.

select * 
from
 t2

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch       68      0.01       0.01          0       1005          0        1000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       70      0.01       0.02          0       1005          0        1000

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 61  

Rows     Row Source Operation
-------  ---------------------------------------------------
   1000  TABLE ACCESS FULL T2 (cr=1005 pr=0 pw=0 time=8348 us)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                      68        0.00          0.00
  SQL*Net more data to client                     2        0.00          0.00
  SQL*Net message from client                    68        0.51         10.46
********************************************************************************


Has Oracle just ignored the time spent on LOB reading? If so, it would be just a sign of bug. But look at following total time in the tkprof report on t1.LOB.

OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        5      0.01       0.00          0          0          0           0
Execute      6      0.00       0.00          0          0          0           0
Fetch     1007      0.14       0.09          0       1009          0        1003
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total     1018      0.15       0.09          0       1009          0        1003

Misses in library cache during parse: 2

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                  102009        0.00          0.31
  SQL*Net message from client                102009        0.03         32.35
  direct path read                           201000        0.06         58.51

...



Look at the times and elapsed time of the wait events! Very strange, isn’t it? The query itself does not include these values, but only the total time includes them. There should be some mismatch. Where does this mismatch happen?

This is the time when we should look into the raw trace file, which is not very common in the real life. See following.

PARSING IN CURSOR #1 len=16 dep=0 uid=61 oct=3 lid=61 tim=155701141356 hv=2245880055 ad='2e6260a8'
select * from t1
END OF STMT
PARSE #1:c=0,e=925,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=155701141350
EXEC #1:c=0,e=56,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=155701142972
WAIT #1: nam='SQL*Net message to client' ela= 5 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=155701143147
WAIT #1: nam='SQL*Net message from client' ela= 358 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=155701143714
WAIT #1: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=155701144019
FETCH #1:c=0,e=312,p=0,cr=4,cu=0,mis=0,r=1,dep=0,og=1,tim=155701144249
WAIT #1: nam='SQL*Net message from client' ela= 161 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=155701144584
WAIT #0: nam='direct path read' ela= 24239 file number=12 first dba=13915 block cnt=1 obj#=89468 tim=155701169489
WAIT #0: nam='direct path read' ela= 440 file number=12 first dba=13915 block cnt=1 obj#=89468 tim=155701170930
WAIT #0: nam='SQL*Net message to client' ela= 4 driver id=1413697536 #bytes=1 p3=0 obj#=89468 tim=155701171143
WAIT #0: nam='SQL*Net message from client' ela= 1273 driver id=1413697536 #bytes=1 p3=0 obj#=89468 tim=155701172643
WAIT #0: nam='direct path read' ela= 26168 file number=12 first dba=13915 block cnt=1 obj#=89468 tim=155701199245
WAIT #0: nam='direct path read' ela= 787 file number=12 first dba=13915 block cnt=1 obj#=89468 tim=155701200504
WAIT #0: nam='SQL*Net message to client' ela= 5 driver id=1413697536 #bytes=1 p3=0 obj#=89468 tim=155701200820
WAIT #0: nam='SQL*Net message from client' ela= 450 driver id=1413697536 #bytes=1 p3=0 obj#=89468 tim=155701201480
...



Do you see the mismatching happening here? CURSOR#1 is the query being executed(select * from t1), but suddenly wait event is reported as WAIT#0 not WAIT#1. This is why we have no wait time in the query itself.

Now comes the difficult part. What the hell is the WAIT#0? Where did it come from? Simple additional test case would give the hints to interpret this phenomenon. While session#1 is reading on t1.LOB, let’s monitor the session#1.

-- session #1(sid=140)
select * from t1;

UKJA@ukja102> -- session #2
UKJA@ukja102> col sql_id new_value v_sql_id
UKJA@ukja102> col prev_sql_id new_value v_prev_sql_id
UKJA@ukja102> col kglnaobj new_value v_kglnaobj
UKJA@ukja102>
UKJA@ukja102> select sql_id, prev_sql_id from v$session where sid = 140
  2  ;

SQL_ID        PREV_SQL_ID
------------- -------------
fa45sbd422h0k 27uhu2q2xuu7r

Elapsed: 00:00:00.01
UKJA@ukja102>-- Note that the CURRENT query is not shown in V$SQL
UKJA@ukja102> select sql_text from v$sql where sql_id = '&v_sql_id';
old   1: select sql_text from v$sql where sql_id = '&v_sql_id'
new   1: select sql_text from v$sql where sql_id = 'fa45sbd422h0k'

no rows selected

Elapsed: 00:00:00.00
UKJA@ukja102>-- The CURRENT query is reported as the PREVIOUS query
UKJA@ukja102> select sql_text from v$sql where sql_id = '&v_prev_sql_id';
old   1: select sql_text from v$sql where sql_id = '&v_prev_sql_id'
new   1: select sql_text from v$sql where sql_id = '27uhu2q2xuu7r'

SQL_TEXT
--------------------------------------------------------------------------------
select * from t1

Elapsed: 00:00:00.01
UKJA@ukja102>-- Although the current query is not existent in the v$sql, 
-- it should exist in the X$KGLOB - the mother of all LCOs
UKJA@ukja102> select kglhdnsp, kglnaobj from sys.xm$kglob where kglobt03 = '&v_sql_id';
old   1: select kglhdnsp, kglnaobj from sys.xm$kglob where kglobt03 = '&v_sql_id'
new   1: select kglhdnsp, kglnaobj from sys.xm$kglob where kglobt03 = 'fa45sbd422h0k'

  KGLHDNSP
----------
KGLNAOBJ
--------------------------------------------------------------------------------
         0
table_4_9_15d7b_0_0_

         0
table_4_9_15d7b_0_0_


Elapsed: 00:00:00.01
UKJA@ukja102>-- What does table_4_9_15d7b_0_0_ mean?
UKJA@ukja102> select object_name from dba_objects
  2  where object_id = to_dec(regexp_substr('&v_kglnaobj',  '[^_]+', 1, 4));
old   2: where object_id = to_dec(regexp_substr('&v_kglnaobj',  '[^_]+', 1, 4))
new   2: where object_id = to_dec(regexp_substr('table_4_9_15d7b_0_0_',  '[^_]+', 1, 4))

OBJECT_NAME
--------------------------------------------------------------------------------
T1



Above result means that

  • When reading LOB, Oracle creates internal cursor which reads the LOB.
  • Because this internal cursor is just another new cursor, the time spent on it is not included in the original query.
  • This internal query does not show itself in the trace file. We can just infer it.
  • Be careful when interpreting the tkprof report, especially when there is a big difference between the time of the individual queries and the total time.

And followings are related posts which describe the same phenomenon in the different ways.
http://kerryosborne.oracle-guy.com/2009/04/hidden-sql-why-cant-i-find-my-sql-text/
https://dioncho.wordpress.com/2009/04/20/lob-sql_id-and-lco/

About these ads

Written by Dion Cho

June 19, 2009 at 2:22 am

Posted in Cursor, Wait Event

2 Responses

Subscribe to comments with RSS.

  1. Nice! That’s why the guys that write the profiling software have such a difficult job.

    The other thing that may be worth noting is that the “SQL*Net message FROM client” event is also misleading. That time is mostly all due to transferring the data TO the client.

    Kerry

    Kerry Osborne

    June 19, 2009 at 1:47 pm

  2. [...] Dion Cho - LOB vs. SQL*Trace [...]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 58 other followers

%d bloggers like this: