Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Rajeshwaran.

Asked: June 22, 2011 - 11:29 am UTC

Last updated: February 11, 2013 - 9:26 am UTC

Version: 10.2.0

Viewed 10K+ times! This question is

You Asked

Tom:

I was reading this Oracle magazine

http://www.oracle.com/technetwork/issue-archive/2011/11-jul/o40asktom-402616.html

<quote>
A full index scan reads the index a block at a time, from start to finish, It uses single-block, not multiblock, I/O for this operation

A fast full index scan reads the entire index, unsorted, as it exists on disk, We use multiblock I/O and read all the leaf, branch, and root blocks
</quote>

create table t
nologging
as
select *
from all_objects;

create index t_ind on t(owner,object_type,object_name) nologging;

begin
 dbms_stats.gather_table_stats(
 ownname =>user,
 tabname =>'T',
 estimate_percent=>dbms_stats.auto_sample_size,
 cascade=>true);
end;
/

rajesh@10GR2>
rajesh@10GR2>
rajesh@10GR2> exec show_space(user,'T_IND','INDEX');
l_total_blocks****************  448
l_total_bytes*****************  yes
l_unused_blocks***************  19
l_unused_bytes****************  155648
l_last_used_extent_file_id****  22
l_last_used_extent_block_id***  4873
l_last_used_block*************  13
l_unformatted_blocks**********  0
l_unformatted_bytes***********  0
l_fs1_blocks******************  0
l_fs1_bytes*******************  0
l_fs2_blocks******************  1
l_fs2_bytes*******************  8192
l_fs3_blocks******************  0
l_fs3_bytes*******************  0
l_fs4_blocks******************  0
l_fs4_bytes*******************  0
l_full_blocks*****************  414
l_full_bytes******************  3391488

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.06
rajesh@10GR2>
rajesh@10GR2>
rajesh@10GR2> set autotrace traceonly explain statistics;
rajesh@10GR2>
rajesh@10GR2> select owner,object_type,object_name
  2  from t
  3  order by owner,object_type,object_name;

58779 rows selected.

Elapsed: 00:00:02.48

Execution Plan
----------------------------------------------------------
Plan hash value: 607953271

--------------------------------------------------------------------------
| Id  | Operation        | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT |       | 58779 |  2296K|   417   (1)| 00:00:06 |
|   1 |  INDEX FULL SCAN | T_IND | 58779 |  2296K|   417   (1)| 00:00:06 |
--------------------------------------------------------------------------


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        803  consistent gets
          0  physical reads
          0  redo size
    1563107  bytes sent via SQL*Net to client
       2984  bytes received via SQL*Net from client
        393  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      58779  rows processed

rajesh@10GR2>
rajesh@10GR2> select owner,object_type,object_name
  2  from t;

58779 rows selected.

Elapsed: 00:00:02.31

Execution Plan
----------------------------------------------------------
Plan hash value: 3351170763

------------------------------------------------------------------------------
| Id  | Operation            | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |       | 58779 |  2296K|    94   (3)| 00:00:02 |
|   1 |  INDEX FAST FULL SCAN| T_IND | 58779 |  2296K|    94   (3)| 00:00:02 |
------------------------------------------------------------------------------


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        810  consistent gets
          1  physical reads
          0  redo size
    1566056  bytes sent via SQL*Net to client
       2984  bytes received via SQL*Net from client
        393  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      58779  rows processed

rajesh@10GR2>
rajesh@10GR2> set autotrace off
rajesh@10GR2>


Questions:

1) Size of index is 429 Blocks (448-19), INDEX FULL SCAN - is doing a single-block IO, if so why the above query needs 803 blocks (from buffer) to answer and why *NOT* 429 blocks?

2) How can i measure the total IO's used by a query? Say in INDEX FULL SCAN we are doing a single-block IO but Autotrace statistics shows that i am reading 803 blocks from buffer to answer this query. How do i know how many IO's is really spent in reading 803 blocks from buffer?

and Tom said...

1) http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:880343948514

it has to do with your arraysize and how many times Oracle has to revisit a block. If you use an arraysize of 2 - you would see about 58779/2 consistent gets. If you use an arraysize of 1000 - you would see about 58779/1000 consistent gets. That above link has examples of this phenomena.

2) You did already? The second query used 810 logical IO's to perform its job. It included one physical IO using multi-block IO (we know it was multi-block IO because we did an index fast full scan)

Consistent gets are always block gets - single block gets. When we are talking "single block IO" and "multiblock IO" - we are talking about a physical IO phenomena. In this case - your index was almost entirely in cache and we didn't really do any physical IO to speak of.

Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Array Size

Rajeshwaran Jeyabal, June 22, 2011 - 1:06 pm UTC

If you use an arraysize of 2 - you would see about 58779/2 consistent gets. If you use an arraysize of 1000 - you would see about 58779/1000 consistent gets


rajesh@10GR2> show arraysize;
arraysize 150
rajesh@10GR2>
rajesh@10GR2> set autotrace traceonly explain statistics;
rajesh@10GR2>
rajesh@10GR2> select owner,object_type,object_name
  2  from t
  3  order by owner,object_type,object_name;

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        803  consistent gets
          0  physical reads
      58779  rows processed

rajesh@10GR2>
rajesh@10GR2> set autotrace off;
rajesh@10GR2>
rajesh@10GR2> select 58779/150 from dual;

 58779/150
----------
    391.86

Elapsed: 00:00:00.01
rajesh@10GR2>


Rows / array_size doesn't match with consistent gets.

rajesh@10GR2> set arraysize 2;
rajesh@10GR2>
rajesh@10GR2> select owner,object_type,object_name
  2  from t
  3  order by owner,object_type,object_name;
  
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      29611  consistent gets
          0  physical reads
          0  redo size
      58779  rows processed

rajesh@10GR2>
rajesh@10GR2>
rajesh@10GR2> set autotrace off
rajesh@10GR2>
rajesh@10GR2> select 58779/2 from dual;

   58779/2
----------
   29389.5

Elapsed: 00:00:00.03
rajesh@10GR2>


Rows / array_size pretty close with consistent gets.

rajesh@10GR2> set arraysize 1000;
rajesh@10GR2>
rajesh@10GR2>
rajesh@10GR2> select owner,object_type,object_name
  2  from t
  3  order by owner,object_type,object_name;

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        473  consistent gets
          0  physical reads
          0  redo size
      58779  rows processed

rajesh@10GR2>
rajesh@10GR2>
rajesh@10GR2> select 58779/1000 from dual;

58779/1000
----------
    58.779

Elapsed: 00:00:00.03
rajesh@10GR2>


Rows / array_size doesn't match with consistent gets.

Tom:
I don't see Rows / array_size match with consistent gets. Is that wrong with Test cases?
Tom Kyte
June 22, 2011 - 1:16 pm UTC

re-read the article I linked to. If you get an understanding of that - you'll get an understanding of these numbers.

It has to do with number of rows per block and how many times we have to read and RE-READ a block.

My math was "simplistic" - there is a diminishing return on larger and larger array fetch sizes - it kicks in at the point where your arraysize exceeds the number of rows on a block *in this particular case*.


Since there are 448 some odd blocks in the structure you are scanning - you'll obviously never go below that.


I should have written:

... - you would see about max( 58779/2, # blocks in structure) consistent gets. If you use an arraysize of 1000 - you would see about max( 58779/1000, # blocks in structure) consistent gets. That above link has examples of this phenomena.


Array Size

Rajeshwaran Jeyabal, June 23, 2011 - 7:26 pm UTC

drop table t purge;
create table t
nologging
as
select * from all_objects;
exec dbms_stats.gather_table_stats(user,'T');
create unique index t_ind on t(object_id) nologging;


rajesh@ORA10GR2> exec show_space(user,'T_IND','INDEX');
l_total_blocks****************  120
l_total_bytes*****************  983040
l_unused_blocks***************  6
l_unused_bytes****************  49152
l_last_used_extent_file_id****  7
l_last_used_extent_block_id***  104841
l_last_used_block*************  2
l_unformatted_blocks**********  0
l_unformatted_bytes***********  0
l_fs1_blocks******************  0
l_fs1_bytes*******************  0
l_fs2_blocks******************  1
l_fs2_bytes*******************  8192
l_fs3_blocks******************  0
l_fs3_bytes*******************  0
l_fs4_blocks******************  0
l_fs4_bytes*******************  0
l_full_blocks*****************  103
l_full_bytes******************  843776

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.37
rajesh@ORA10GR2>
rajesh@ORA10GR2> select 120 - 6 from dual;

     120-6
----------
       114

Elapsed: 00:00:00.01
rajesh@ORA10GR2>


So, The total size of Index is 114 Blocks.

rajesh@ORA10GR2> show arraysize;
arraysize 150
rajesh@ORA10GR2> set autotrace traceonly statistics;
rajesh@ORA10GR2>
rajesh@ORA10GR2> select object_id from t;

Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        442  consistent gets
        109  physical reads
      49867  rows processed

rajesh@ORA10GR2>
rajesh@ORA10GR2> select (49867/150)+114 from dual;

(49867/150)+114
---------------
     446.446667


Now the Consistent gets maches with calculation (for arraysize=150).

rajesh@ORA10GR2> show arraysize;
arraysize 2
rajesh@ORA10GR2> select object_id from t;

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      24992  consistent gets
          0  physical reads
      49867  rows processed

rajesh@ORA10GR2> select (49867/2)+114 from dual;

(49867/2)+114
-------------
      25047.5

Elapsed: 00:00:00.03
rajesh@ORA10GR2>


Now the Consistent gets maches with calculation (for arraysize=2).

http://download.oracle.com/docs/cd/B19306_01/server.102/b14357/ch8.htm#sthref1561

Documentation says that ArraySize Valid values are 1 to 5000

rajesh@ORA10GR2> set arraysize 1;
rajesh@ORA10GR2> show arraysize;
arraysize 1
rajesh@ORA10GR2>
rajesh@ORA10GR2> select object_id from t;

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      24992  consistent gets
          0  physical reads
      49867  rows processed

rajesh@ORA10GR2>
rajesh@ORA10GR2> select (49867/1)+114 from dual;

(49867/1)+114
-------------
        49981

Elapsed: 00:00:00.03
rajesh@ORA10GR2>


Tom:

1) Setting ArraySize=1 Consistent gets doesnot match with calculation. So setting ArraySize=1 is treated as Arraysize=2 ? If yes, then why doc's say that Valid values are 1 to 5000. is that a doc's bug?

PS: Setting ArraySize=1 in 11.2.1.0 has the same problem.

Even 11.2 Doc's says Valid values are 1 to 5000.
http://download.oracle.com/docs/cd/E11882_01/server.112/e16604/ch_eight.htm#sthref928
Tom Kyte
June 24, 2011 - 8:48 am UTC

1) sqlplus does that, its smallest array fetch size is 2 under the covers. You can verify that yourself by tracing the application and looking at the r= value on the FETCH records.

Value values are 1 to 5000 - you set it to one, it is valid.

It is just done using 2 - by design.

Array Size - RAC (3 Instance)

Rajeshwaran, Jeyabal, June 25, 2011 - 11:15 am UTC

drop table t purge;
create table t
nologging
as
select * 
from all_objects;
exec dbms_stats.gather_table_stats(user,'T');
exec show_space(user,'T','TABLE');


rajesh@ORA10GR2> select instance_number,instance_name from gv$instance;

INSTANCE_NUMBER INSTANCE_NAME
--------------- ----------------
              1 ORA10G011
              3 ORA10G013
              2 ORA10G012

Elapsed: 00:00:00.06
rajesh@ORA10GR2>
rajesh@ORA10GR2> exec show_space(user,'T','TABLE');
l_total_blocks****************  768
l_total_bytes*****************  6291456
l_unused_blocks***************  16
l_unused_bytes****************  131072
l_last_used_extent_file_id****  204
l_last_used_extent_block_id***  91017
l_last_used_block*************  112
l_unformatted_blocks**********  0
l_unformatted_bytes***********  0
l_fs1_blocks******************  0
l_fs1_bytes*******************  0
l_fs2_blocks******************  0
l_fs2_bytes*******************  0
l_fs3_blocks******************  0
l_fs3_bytes*******************  0
l_fs4_blocks******************  0
l_fs4_bytes*******************  0
l_full_blocks*****************  732
l_full_bytes******************  5996544

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
rajesh@ORA10GR2>
rajesh@ORA10GR2> select 768 - 16 from dual;

    768-16
----------
       752

Elapsed: 00:00:00.01
rajesh@ORA10GR2>
rajesh@ORA10GR2> show arraysize ;
arraysize 150
rajesh@ORA10GR2>
rajesh@ORA10GR2> set autotrace traceonly statistics;
rajesh@ORA10GR2>
rajesh@ORA10GR2> select object_name,object_type,status
  2  from all_objects;

52237 rows selected.

Elapsed: 00:00:02.73

Statistics
----------------------------------------------------------
       4278  recursive calls
          0  db block gets
     105299  consistent gets
          0  physical reads
          0  redo size
    1367052  bytes sent via SQL*Net to client
       4178  bytes received via SQL*Net from client
        350  SQL*Net roundtrips to/from client
        711  sorts (memory)
          0  sorts (disk)
      52237  rows processed

rajesh@ORA10GR2>
rajesh@ORA10GR2> set autotrace off;
rajesh@ORA10GR2> set autotrace traceonly statistics;
rajesh@ORA10GR2> /

52237 rows selected.

Elapsed: 00:00:02.79

Statistics
----------------------------------------------------------
       4278  recursive calls
          0  db block gets
     105299  consistent gets
          0  physical reads
          0  redo size
    1367052  bytes sent via SQL*Net to client
       4178  bytes received via SQL*Net from client
        350  SQL*Net roundtrips to/from client
        711  sorts (memory)
          0  sorts (disk)
      52237  rows processed

rajesh@ORA10GR2> set autotrace off;
rajesh@ORA10GR2>
rajesh@ORA10GR2>
rajesh@ORA10GR2> select (52237/150) + 752 from dual;

(52237/150)+752
---------------
     1100.24667

Elapsed: 00:00:00.01
rajesh@ORA10GR2>


Questions

1) Why this Consistent gets **NOT** maches with calculation in 3 Instance RAC database? Does this calculation doesn't work for RAC database?

2) <qutoe - Effective Oracle by design>
If the recursive calls number is initially high, I may run the query again and see if this statistic remains high. If it doesn’t, that would indicate the recursive SQL was due to a hard parse.
</quote>
Why the recursive call for the above query is still high?
Tom Kyte
June 25, 2011 - 11:27 am UTC

you cannot take a quote out of context like that, I was talking about MY recursive calls in MY example under MY circumstances. I was not making a statement that recursive calls are only for hard parsing. Many things cause them.


turn on sql trace, take a look at your trace file, see what is going on - just like I would do - just like I do do for you - when demonstrating things. trace it, see what is happening.

Single block and Multi block Access path

Rajeshwaran, Jeyabal, February 08, 2013 - 7:21 am UTC

Tom,

Can you explain what access path's are single block and multi block IO's ? and how to identify a particular access path is Single or multiblock IO's ?

Single block IO
1) Index range scan+ Table access by rowid
2) Index full scan

Multi block IO
1) Index Fast Full scan
2) Table full Scan
Tom Kyte
February 11, 2013 - 9:26 am UTC

you already listed them?

table full scans and index fast full scans are multiblock IO

the rest are single block IO access paths.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library