Posts mit dem Label event 10046 werden angezeigt. Alle Posts anzeigen
Posts mit dem Label event 10046 werden angezeigt. Alle Posts anzeigen

2014-10-07

enhanced SQL trace

As a huge friend of Oracles SQL trace I also see it's limitations as well. One of these limitations is visible in it's underlying infrastructure: the wait interface. It's only about waits.
There is another source of information as well, you could call it the DO interface, but the common term is session and system statistics. there Oracle counts what it is doing.
Unfortunately I do not know a simple way to show both realities in a common way.

At least for consistent gets I now can show (most of) them together with wait events.

The magic is done by event 10200 - Dump Consistent Reads.

I create a trace file with both, 10046 and 10200 event:


SET AUTOTRACE ON STATISTICS

ALTER SESSION SET EVENTS '10200 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER, LEVEL 8';

select * from berx.t1;

Statistics
----------------------------------------------------------
         80  recursive calls
          0  db block gets
        118  consistent gets
          0  physical reads
          0  redo size
        654  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
         15  sorts (memory)
          0  sorts (disk)
          3  rows processed

Of course the additional event gives additional lines which will not be processed by those tools to parse SQL traces. I will not go into any detail of those additional lines - especially as I don't know about them to much. If you are interested I'd recommend Charles Hoopers blog.

I just grab lines which contain the string completed for block and rework their values so it looks similar to something the SQL trace parsers know. This is a very inexperienced piece of code!

#!/usr/bin/perl -w
#10200_preproc.pl
use strict;

my $cursor       = 0 ;
my $timestamp    = 0 ;
my $is_processed = 0 ;
my $tablespace;
my $block;
my $object_id;

while (<>) {
  my $line = $_;
  if ($line =~ m/.*#(\d+)[: ].*/) {
    ($cursor = $line) =~ s/.*#(\d+)[: ].*/$1/ ;
  }
  $cursor =~ tr/\n//d;

  if ($line =~ m/.*tim=(\d+).*/) {
    ($timestamp = $line) =~ s/.*#(\d+)[: ].*/$1/ ;
  }
  $timestamp =~ tr/\n//d;

  if ($line =~ m/completed for block/) {
    ($tablespace = $line) =~ s/.*\<([abcdefx\d]+) : .*/$1/ ;
    ($block      = $line) =~ s/.* : ([abcdefx\d]+).*/$1/;
    ($object_id  = $line) =~ s/.*objd: ([abcdefx\d]+).*/$1/;
    $tablespace =~ tr/\n//d;
    $block      =~ tr/\n//d;
    $object_id  =~ tr/\n//d;
    $tablespace = hex($tablespace) +1;
    $block      = hex($block);
    $object_id  = hex($object_id);
# WAIT #391723720: nam='db file scattered read' ela= 2876 file#=5 block#=129 blocks=127 obj#=71123 tim=90982740602
    print "WAIT #"; # as the hash is somethign special ...
    print "$cursor: nam='LIO - completed for block' ela=0 tablespace=$tablespace block#=$block obj=$object_id obj#=$object_id tim=$timestamp\n";
    $is_processed = 1;

  }
  if ($is_processed == 0) {
    print $line;
  }
  else {
    $is_processed = 0
  }

}

This code should really be seen as an example, not a solution!
Out of a line like
ktrgcm(): completed for block  <0x0000 : 0x0041560c> objd: 0x0000003e
it creates
WAIT #47572859450312: nam='LIO - completed for block' ela=0 tablespace=1 block#=4281868 obj=62 obj#=62 tim=47572859450312

Probably the only magic is the Cursor and timing info which I just copy from the last SQL trace line above. I'd as well like not to use the keyword WAIT as for sure the process is not waiting in this case, but I have to still trick the tools.

With my modified tracefile from the statement above I create this report:

CALL-NAME                    DURATION       %  CALLS      MEAN       MIN       MAX
---------------------------  --------  ------  -----  --------  --------  --------
SQL*Net message from client  0.671976   95.8%      3  0.223992  0.000165  0.671529
PARSE                        0.025995    3.7%      1  0.025995  0.025995  0.025995
row cache lock               0.001640    0.2%     12  0.000137  0.000079  0.000497
FETCH                        0.001000    0.1%      2  0.000500  0.000000  0.001000
library cache pin            0.000471    0.1%      2  0.000236  0.000214  0.000257
library cache lock           0.000443    0.1%      2  0.000222  0.000211  0.000232
Disk file operations I/O     0.000047    0.0%      1  0.000047  0.000047  0.000047
SQL*Net message to client    0.000002    0.0%      3  0.000001  0.000000  0.000001
LIO - completed for block    0.000000    0.0%    117  0.000000  0.000000  0.000000
CLOSE                        0.000000    0.0%      3  0.000000  0.000000  0.000000
EXEC                         0.000000    0.0%      1  0.000000  0.000000  0.000000
XCTEND                       0.000000    0.0%      1  0.000000  0.000000  0.000000
---------------------------  --------  ------  -----  --------  --------  --------
TOTAL (12)                   0.701574  100.0%    148  0.004740  0.000000  0.671529

You see 117 LIO - completed for block events here, which is quite close to 118 consistent gets.

There are probably a lot more things to do, still it helps me to show what a statement is doing (in terms of LIO) beside the time it spends waiting.

2008-12-28

no row information in data dictionary

It all began with a simple question how to get all ROWIDs from a table (without selecting it)? I posted on oracle-l. After some private forks of conversations I got an email by Jared Still where he mentioned:
"If you constructed a rowid, and did a select on the row, it probably doesn't
matter if the row exists or not.

Oracle has to read the block from disk to read the row directory.
The block would get cached whether or not the row exists.

I haven't tested this, but I imagine you will.  :)
"
Of course, he was right:
My testcase was very simple:

  1. preparation
     create table jared as select * from dual;
  2. testcase
    ALTER SESSION SET events '10046 trace name context forever, level 12';
    
    Session altered.
    
    select * from jared where rowid='AAAPa5AABAAATHhAAB';
    
    no rows selected
    
    /
    
    no rows selected
    
    select * from jared where rowid='AAAPa5AABAAATHhAAA';
    
    D
    -
    X
    
    which created a tracefile.
  3. summary
    the first statement hase one related wait: 'db file sequential read' the second and the third have no such waits!
    I crosschecked the situation by asking the buffer:


    select tch from x$bh where obj=63161 and dbablk=78305 and dbarfil=1;
    and - as expected - it just counted up from no rows selected (before the first run) counting 1, 2, 3.
  4. conclusio
    Disclaimer: Even I hope it's well coated, I never can be 100% sure. A modern RDBMS has so many ways to do it's job I would have to ask the developers to prove. (which I can't).

    • the buffer_cache caches blocks, not rows. (obvious?)
    • even if a row does not exist, it's including block is cached, if it's available.
    • as the smallest granularity the RDBMS takes care at IO is a block, and it even stores blocks if the row asked for does not exist.
    this brings me to my own answer to my initial question:
    There is no ROWID information for a given table stored in data dictionary.

2008-08-29

gc current block 2-way - p1,p2,p3

In some tracing I stumbled about a lot of lines like this:

nam='gc current block 2-way' ela= 1716 p1=7 p2=449034 p3=33554433 obj#=61165 tim=1190815206676979

Even I know the Interconnect is too slow (only 100MBit), I just want to know what I read here. (at least the best way I can do).
the meaning of ela=, obj#= and tim= can be found on many places. But the p1, p2 and p3 where of some interrest. So I started to search. but neither Metalink nor Oracle-L could answer my search-results (maybe I just used the wrong words?) There where even no other direct source I could find.
I also run

SELECT name, parameter1, parameter2, parameter3
FROM V$EVENT_NAME
WHERE name like 'gc current block %way';

and got

NAME P1 P2 P3
------------------------ ----- ----- -----
gc current block 2-way
gc current block 3-way

back.
there is also nothing in the 11g documentation about gc current block.

Not so good informations so far. This led me to a searching marathon:
(only my findings)
  • The Book Oracle 10g RAC Grid, Services & Clustering gives a link between gc current block 2-way (10g Wait name) and global cache open x (9i Wait name).
  • The Book Oracle Wait Interface tells me about global cache open x: 

    global cache open x
    Wait Parameters
    Wait parameters for global cache open x are described here:

    P1 File number from which Oracle is reading the block
    P2 Block number from the file that Oracle wants to read into a buffer
    P3 The lock element number or class of the buffer

  • one more finding (from limited value): in the docu there is an event GCS lock open X which seems to have the same content for P1, P2 and P3. But of course a 'lock open' is not simply equal to a 'cache open' or a request for a 'current block'.

So far for the (very limited) documentation I found.
Now let's do some tests (on an other DB):

  1. instance 1: create table test1 as select * from dba_objects;

  2. instance 1: select * from test1;27 cr multi block request, 2 gc cr grant 2-way. I don't know where they come from(!) this will be matter for further investigations.

  3. instance 1: select * From test1;no gc cr ... only SQL*Net message

  4. instance 2: select * from test1; this is the most interresting part: a lot of differnt waits, most interresting is:
    WAIT #1: nam='gc cr multi block request' ela= 144 file#=6 block#=48017 class#=1 obj#=62850 tim=685587786409
    WAIT #1: nam='gc current block 2-way' ela= 1121 p1=6 p2=48018 p3=1 obj#=62850 tim=685588475668

    looking down for 6. ( i run it with 48017 and 48018) I can at least compare file# to p1 and block# to p2 - obj# also matches

  5. instance 2: select * From test1;only one library cache lock and of course SQL*Net message

  6.  SELECT segment_name
    FROM dba_segments
    WHERE header_file=6 and 48017 between HEADER_BLOCK and HEADER_BLOCK+blocks;


    SEGMENT_NAME
    ------------
    TEST1

    and
    SELECT OBJECT_NAME, OBJECT_ID
    FROM dba_objects
    WHERE OBJECT_ID=62850;

    OBJECT_NAME OBJECT_ID
    ----------- ----------
    TEST1 62850


Conclusio:

So my findings are:

  1. more questions, e.g. why are there any gc in the 1st select?
  2. Even I still cannot proove, I assume p1, p2 and p3 of gc current block 2-way (and mayby also others) match to file#, block# (and maybe also class# - even I have not thought about this!)