Skip to Main Content
  • Questions
  • DB_FILE_MULTI_BLOCK_READ_COUNT According with SAME Metodology

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Jose Eduardo.

Asked: January 02, 2006 - 6:46 pm UTC

Last updated: February 06, 2017 - 2:52 pm UTC

Version: 9.2.0.5.0

Viewed 1000+ times

You Asked

Hi, I'm configuring my Database/Storage (HP-XP12K) and I want to do this by follow the SAME Metodology (Doc. "Optimal Storage Configuration Made Easy" by Juan Loaiza) to do this, but there is a part in the document that stablish that you need to put the DB_FILE_MULTI_BLOCK_READ_COUNT parameter to 1MB. So, How can I accomplish this if I my RDBMS environment is an OLTP and I have 8K for db_block_size? (Eg. 1024/8=128). My actual value is 16.


and Tom said...

If you are OLTP you do not anticipate doing full scans - so this setting would be relatively meaningless.

I would back away from their recommendation and let this value DEFAULT.



Rating

  (23 ratings)

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

Comments

Cake and eat it as well

Connor, January 03, 2006 - 4:50 am UTC

A practical alternative to get both maximum tablescan performance without biasing the optimizer toward full scans is to set db_file_multiblock_read_count to 128, and set MBRC (via dbms_stats) to (say) 8, along with the other system stats.

hth
connor

Tom Kyte
January 03, 2006 - 7:39 am UTC

That is an interesting one - nice.

Can I taste the cake ?

syed, January 04, 2006 - 6:18 am UTC

Hi Connor / Tom

could you explain a bit more about setting MBRC via DBMS_STATS ?

I'm guessing this is a 10g thing ?

Regards

Syed

Tom Kyte
January 04, 2006 - 10:30 am UTC

9iR2 - see dbms_stats, gathering and setting system statistics. You have the ability to either gather the real numbers from your system or to "tell" us about them.

<quote src=Effective Oracle by Design>
Use SYSTEM Statistics

Oracle9i introduced an alternative to OPTIMIZER_INDEX_COST_ADJ and OPTIMIZER_INDEX_CACHING that is worth a serious look. The DBMS_STATS package was enhanced to collect a new type of statistic: system statistics. These statistics measure actual performance characteristics of your unique system. They measure your actual CPU and disk-performance characteristics using your actual workloads. They are not guesses. They are actual, measured observations of what has occurred in your system during the period of measurement. Depending on the type of work you actually perform, different costs will be associated with various operations, affecting the eventual query plans that result.
Every physical configuration will perform a little differently than any other configuration. That is why the perfect numbers for the OPTIMIZER_INDEX_* parameters cannot simply be stated. The best numbers rely on your systems fingerprint-its unique characteristics. Hence, the ability for us to measure, collect, and then use actual performance characteristics of our systems can reduce or remove the need to guess at these figures.
System statistics gathering works in one of two ways:

You tell Oracle to start measuring now, and then after a while, you tell it to stop measuring now.
You tell Oracle to measure system statistics for the next <some period of time>, and Oracle will start and stop by itself.

</quote>


note: in 10g there are even more options



Time for a re-read !

A reader, January 06, 2006 - 9:30 am UTC

Thanks

as I have your book - i'd better re-read it !

Thanks

Syed

Solution does work

Christo Kutrovsky, January 09, 2006 - 2:24 pm UTC

I just wanted to mention that I've reached the same conclusions as what Connor suggested.

In my extensive IO testing, it has proven that large MBRC are giving the best results (1Mb is pretty good).

I was still not able to reach full capacity on my fibre channels thow. Only parallel query (or 2 queries doing FTS) were able to push all the way to 200 Mb/sec no matter how big MBRC.



multiblock setting

mal, May 15, 2006 - 2:48 pm UTC

The setting of db_file_multiblock_read_count dictates how many I/O calls will be required to complete a table scan. For example, if db_file_multiblock_read_count is set to 32, and the Oracle block size = 8k, then a sequential scan of a 256k table can be read in one pass. This improves the speed of the table scan and overall query performance. The cost of setting db_file_multiblock_read_count too high is that the server will consume additional memory and may cause full table scans to be chosen by the Cost-Based Optimizer more frequently.

The maximum value of the overall multiblock read factor is calculated as:
(db_block_size * db_file_multiblock_read_count)

Oracle's ability to read multiple blocks is limited by the operating system's upper limit on the
number of bytes which can be read in a single I/O call (MAX_IO_SIZE). If the
value of db_file_multiblock_read_count exceeds internal constraints on the
setting, it will default to the O/S default: (max_IO_size / db_block_size).

Our OS max IO size is 64k so
We have

DB_BLOCK_SIZE x DB_FILE_MULTIBLOCK_READ_COUNT = max_io_size of system

8k * 16 = 128k


Suggested:

DB_BLOCK_SIZE x DB_FILE_MULTIBLOCK_READ_COUNT = max_io_size of system

8k * 8 = 64k

Tom,

Do you think above suggestion make sense?

Tom Kyte
May 15, 2006 - 3:51 pm UTC

I would say "db file multiblock read count places an upper limit on the IO size Oracle will use"

It does NOT "dictates how many I/O calls will be required to complete a table scan. "


If I had a 128 block table
And db file mbrc (multi block read count) was set to 64
It could take 64 physical IO's :)

ops$tkyte@ORA10GR2> create table t ( x int, y int ) tablespace manual;

Table created.

ops$tkyte@ORA10GR2> insert into t values ( 1, 1 );

1 row created.

ops$tkyte@ORA10GR2> insert into t values ( 2, 1 );

1 row created.

ops$tkyte@ORA10GR2> alter table t minimize records_per_block;

Table altered.

ops$tkyte@ORA10GR2> insert into t select rownum+2, 1 from all_objects where rownum <= 254;

254 rows created.

ops$tkyte@ORA10GR2> create index t_idx on t(x);

Index created.

ops$tkyte@ORA10GR2> exec dbms_stats.gather_table_stats( user, 'T' );

PL/SQL procedure successfully completed.

ops$tkyte@ORA10GR2> select count(distinct dbms_rowid.rowid_block_number(rowid)) from t;

COUNT(DISTINCTDBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID))
---------------------------------------------------
                                                128

ops$tkyte@ORA10GR2> alter system flush buffer_cache;

System altered.

ops$tkyte@ORA10GR2> alter session set db_file_multiblock_read_count = 64;

Session altered.

ops$tkyte@ORA10GR2> declare
  2          l_y number;
  3  begin
  4          for i in 1 .. 64
  5          loop
  6                  select y into l_y from t where x = i*4;
  7          end loop;
  8  end;
  9  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA10GR2> column trace new_value trace
ops$tkyte@ORA10GR2> select c.value || '/' || d.instance_name || '_ora_' || a.spid || '.trc' trace
  2    from v$process a, v$session b, v$parameter c, v$instance d
  3   where a.addr = b.paddr
  4     and b.audsid = userenv('sessionid')
  5     and c.name = 'user_dump_dest'
  6  /

TRACE
-------------------------------------------------------------------------------
/home/ora10gr2/admin/ora10gr2/udump/ora10gr2_ora_22450.trc

ops$tkyte@ORA10GR2> @trace
ops$tkyte@ORA10GR2> alter session set events '10046 trace name context forever, level 12';

Session altered.

ops$tkyte@ORA10GR2> set autotrace traceonly statistics;
ops$tkyte@ORA10GR2> select * from t;

256 rows selected.


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        145  consistent gets
         69  physical reads
          0  redo size
       4812  bytes sent via SQL*Net to client
        572  bytes received via SQL*Net from client
         19  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        256  rows processed

ops$tkyte@ORA10GR2> connect /
Connected.
ops$tkyte@ORA10GR2> !grep sequential &TRACE
WAIT #27: nam='db file sequential read' ela= 65 file#=20 block#=1937 blocks=1 obj#=65104 tim=1120822201463912
WAIT #27: nam='db file sequential read' ela= 35 file#=20 block#=1938 blocks=1 obj#=65104 tim=1120822201464177
WAIT #27: nam='db file sequential read' ela= 52 file#=20 block#=1940 blocks=1 obj#=65104 tim=1120822201465441
WAIT #27: nam='db file sequential read' ela= 33 file#=20 block#=1942 blocks=1 obj#=65104 tim=1120822201465600
WAIT #27: nam='db file sequential read' ela= 34 file#=20 block#=1944 blocks=1 obj#=65104 tim=1120822201465689
WAIT #27: nam='db file sequential read' ela= 43 file#=20 block#=1946 blocks=1 obj#=65104 tim=1120822201466583
WAIT #27: nam='db file sequential read' ela= 37 file#=20 block#=1948 blocks=1 obj#=65104 tim=1120822201466796
WAIT #27: nam='db file sequential read' ela= 42 file#=20 block#=1950 blocks=1 obj#=65104 tim=1120822201466914
WAIT #27: nam='db file sequential read' ela= 27 file#=20 block#=1952 blocks=1 obj#=65104 tim=1120822201467000
WAIT #27: nam='db file sequential read' ela= 68 file#=20 block#=1954 blocks=1 obj#=65104 tim=1120822201467904
WAIT #27: nam='db file sequential read' ela= 24 file#=20 block#=1956 blocks=1 obj#=65104 tim=1120822201468038
WAIT #27: nam='db file sequential read' ela= 16 file#=20 block#=1958 blocks=1 obj#=65104 tim=1120822201468119
WAIT #27: nam='db file sequential read' ela= 16 file#=20 block#=1960 blocks=1 obj#=65104 tim=1120822201468172
WAIT #27: nam='db file sequential read' ela= 26 file#=20 block#=1962 blocks=1 obj#=65104 tim=1120822201468626
WAIT #27: nam='db file sequential read' ela= 20 file#=20 block#=1964 blocks=1 obj#=65104 tim=1120822201468727
WAIT #27: nam='db file sequential read' ela= 26 file#=20 block#=1966 blocks=1 obj#=65104 tim=1120822201468818
WAIT #27: nam='db file sequential read' ela= 22 file#=20 block#=1968 blocks=1 obj#=65104 tim=1120822201468901
WAIT #27: nam='db file sequential read' ela= 27 file#=20 block#=1970 blocks=1 obj#=65104 tim=1120822201469467
WAIT #27: nam='db file sequential read' ela= 16 file#=20 block#=1972 blocks=1 obj#=65104 tim=1120822201469555
WAIT #27: nam='db file sequential read' ela= 18 file#=20 block#=1974 blocks=1 obj#=65104 tim=1120822201469745
WAIT #27: nam='db file sequential read' ela= 27 file#=20 block#=1976 blocks=1 obj#=65104 tim=1120822201470125
WAIT #27: nam='db file sequential read' ela= 15 file#=20 block#=1978 blocks=1 obj#=65104 tim=1120822201470260
WAIT #27: nam='db file sequential read' ela= 15 file#=20 block#=1980 blocks=1 obj#=65104 tim=1120822201470340
WAIT #27: nam='db file sequential read' ela= 15 file#=20 block#=1982 blocks=1 obj#=65104 tim=1120822201470416
WAIT #27: nam='db file sequential read' ela= 39 file#=20 block#=1984 blocks=1 obj#=65104 tim=1120822201470926
WAIT #27: nam='db file sequential read' ela= 33 file#=20 block#=1986 blocks=1 obj#=65104 tim=1120822201471052
WAIT #27: nam='db file sequential read' ela= 20 file#=20 block#=1988 blocks=1 obj#=65104 tim=1120822201471147
WAIT #27: nam='db file sequential read' ela= 23 file#=20 block#=1990 blocks=1 obj#=65104 tim=1120822201471281
WAIT #27: nam='db file sequential read' ela= 31 file#=20 block#=1992 blocks=1 obj#=65104 tim=1120822201471953
WAIT #27: nam='db file sequential read' ela= 22 file#=20 block#=1994 blocks=1 obj#=65104 tim=1120822201472060
WAIT #27: nam='db file sequential read' ela= 22 file#=20 block#=1996 blocks=1 obj#=65104 tim=1120822201472152
WAIT #27: nam='db file sequential read' ela= 26 file#=20 block#=1998 blocks=1 obj#=65104 tim=1120822201472240
WAIT #27: nam='db file sequential read' ela= 34 file#=20 block#=2000 blocks=1 obj#=65104 tim=1120822201472704
WAIT #27: nam='db file sequential read' ela= 23 file#=20 block#=2002 blocks=1 obj#=65104 tim=1120822201472823
WAIT #27: nam='db file sequential read' ela= 17 file#=20 block#=2004 blocks=1 obj#=65104 tim=1120822201472914
WAIT #27: nam='db file sequential read' ela= 26 file#=20 block#=2006 blocks=1 obj#=65104 tim=1120822201473325
WAIT #27: nam='db file sequential read' ela= 136 file#=20 block#=2008 blocks=1 obj#=65104 tim=1120822201473564
WAIT #27: nam='db file sequential read' ela= 28 file#=20 block#=2010 blocks=1 obj#=65104 tim=1120822201473671
WAIT #27: nam='db file sequential read' ela= 30 file#=20 block#=2012 blocks=1 obj#=65104 tim=1120822201473778
WAIT #27: nam='db file sequential read' ela= 22 file#=20 block#=2014 blocks=1 obj#=65104 tim=1120822201474305
WAIT #27: nam='db file sequential read' ela= 21 file#=20 block#=2016 blocks=1 obj#=65104 tim=1120822201474380
WAIT #27: nam='db file sequential read' ela= 16 file#=20 block#=2018 blocks=1 obj#=65104 tim=1120822201474481
WAIT #27: nam='db file sequential read' ela= 32 file#=20 block#=2020 blocks=1 obj#=65104 tim=1120822201474584
WAIT #27: nam='db file sequential read' ela= 29 file#=20 block#=2022 blocks=1 obj#=65104 tim=1120822201475185
WAIT #27: nam='db file sequential read' ela= 20 file#=20 block#=2024 blocks=1 obj#=65104 tim=1120822201475265
WAIT #27: nam='db file sequential read' ela= 23 file#=20 block#=2026 blocks=1 obj#=65104 tim=1120822201475357
WAIT #27: nam='db file sequential read' ela= 18 file#=20 block#=2028 blocks=1 obj#=65104 tim=1120822201475545
WAIT #27: nam='db file sequential read' ela= 19 file#=20 block#=2030 blocks=1 obj#=65104 tim=1120822201475992
WAIT #27: nam='db file sequential read' ela= 11 file#=20 block#=2032 blocks=1 obj#=65104 tim=1120822201476049
WAIT #27: nam='db file sequential read' ela= 13 file#=20 block#=2034 blocks=1 obj#=65104 tim=1120822201476125
WAIT #27: nam='db file sequential read' ela= 32 file#=20 block#=2036 blocks=1 obj#=65104 tim=1120822201476477
WAIT #27: nam='db file sequential read' ela= 17 file#=20 block#=2038 blocks=1 obj#=65104 tim=1120822201476623
WAIT #27: nam='db file sequential read' ela= 13 file#=20 block#=2040 blocks=1 obj#=65104 tim=1120822201476700
WAIT #27: nam='db file sequential read' ela= 16 file#=20 block#=2042 blocks=1 obj#=65104 tim=1120822201476786
WAIT #27: nam='db file sequential read' ela= 24 file#=20 block#=2044 blocks=1 obj#=65104 tim=1120822201477185
WAIT #27: nam='db file sequential read' ela= 13 file#=20 block#=2046 blocks=1 obj#=65104 tim=1120822201477271
WAIT #27: nam='db file sequential read' ela= 12 file#=20 block#=2048 blocks=1 obj#=65104 tim=1120822201477429
WAIT #27: nam='db file sequential read' ela= 14 file#=20 block#=2050 blocks=1 obj#=65104 tim=1120822201477515
WAIT #27: nam='db file sequential read' ela= 17 file#=20 block#=2052 blocks=1 obj#=65104 tim=1120822201477922
WAIT #27: nam='db file sequential read' ela= 16 file#=20 block#=2054 blocks=1 obj#=65104 tim=1120822201478011
WAIT #27: nam='db file sequential read' ela= 14 file#=20 block#=2056 blocks=1 obj#=65104 tim=1120822201478066
WAIT #27: nam='db file sequential read' ela= 16 file#=20 block#=2186 blocks=1 obj#=65104 tim=1120822201478148
WAIT #27: nam='db file sequential read' ela= 21 file#=20 block#=2188 blocks=1 obj#=65104 tim=1120822201478577
WAIT #27: nam='db file sequential read' ela= 16 file#=20 block#=2190 blocks=1 obj#=65104 tim=1120822201478684
WAIT #27: nam='db file sequential read' ela= 18 file#=20 block#=2192 blocks=1 obj#=65104 tim=1120822201478744

ops$tkyte@ORA10GR2> !grep sequential &TRACE | wc
     65     845    7151


<b>because I loaded every other block into the cache via the index access - the full scan used single block IO as well - dbms_stats.gather_system_stats can be used to measure your TRUE multi-block IO experience :)</b>

If you gather system statistics, we'll measure your ACTUAL observed multiblock IO and that is what'll be used by the CBO.

But if your max io size is in fact 64k (seems low?) - then setting it to a value that gives you 64k would not likely "hurt", although I always recommend "defaulting" it.
 

mbrc setting

mal, May 15, 2006 - 4:54 pm UTC

That's very nice example :)
Our OS max IO size is 64k so
We have

DB_BLOCK_SIZE x DB_FILE_MULTIBLOCK_READ_COUNT = max_io_size of system

8k * 16 = 128k


Suggested:

DB_BLOCK_SIZE x DB_FILE_MULTIBLOCK_READ_COUNT = max_io_size of system

8k * 8 = 64k

Tom,

Do you think above suggestion make sense?

Tom Kyte
May 15, 2006 - 4:57 pm UTC

Like I said "default it", unless you have a compelling reason to change it. Best to leave the defaults in place.



mdrc

mal, May 15, 2006 - 5:34 pm UTC

 


SQL> create table t ( x int, y int ) tablespace  users;

Table created.

SQL> insert into t values ( 1, 1 );

1 row created.

SQL> insert into t values ( 2, 1 );

1 row created.

SQL> insert into t select rownum+2, 1 from all_objects where 
  2  rownum <= 254;

254 rows created.

SQL> create index t_idx on t(x);

Index created.

  


SQL> exec dbms_stats.gather_table_stats( user, 'T' );

PL/SQL procedure successfully completed.

SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)) 
  2  from t;

COUNT(DISTINCTDBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID))
---------------------------------------------------
                                                  1

SQL> alter system flush buffer_cache;
alter system flush buffer_cache
                   *
ERROR at line 1:
ORA-02000: missing SHARED_POOL keyword


SQL> alter session set db_file_multiblock_read_count = 64;

Session altered.


SQL> declare
  2              l_y number;
  3      begin
  4              for i in 1 .. 64
  5              loop
  6                      select y into l_y from t where x = i*4;
  7              end loop;
  8      end;
  9  /

PL/SQL procedure successfully completed.

SQL> column trace new_value trace
SQL> select c.value || '/' || d.instance_name || '_ora_' || 
  2  a.spid || '.trc' trace
  3       from v$process a, v$session b, v$parameter c, v$instance d
  4       where a.addr = b.paddr
  5         and b.audsid = userenv('sessionid')
  6         and c.name = 'user_dump_dest';

TRACE
--------------------------------------------------------------------------------
/home/app/oracle/admin/MERCA/udump/MERCA1_ora_13249.trc

SQL> alter session set events '10046 trace name context forever, 
  2  level 12';

Session altered.

 
SQL> set autotrace traceonly statistics;
SQL> 

SQL> select * from t;

256 rows selected.


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         24  consistent gets
          0  physical reads
          0  redo size
       4703  bytes sent via SQL*Net to client
        690  bytes received via SQL*Net from client
         19  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        256  rows processed


[oracle@dbtest01 MERCA1 udump]$ grep sequential MERCA1_ora_13249.trc | wc
      0       0       0

Now please help me to understand what does it mean? 

Tom Kyte
May 15, 2006 - 6:11 pm UTC

you are on a version that does not support "flush buffer cache"

so, you can offline and online your tablespace which will have a similar effect.

Or you can just trust that I actually cut and paste things :)

You skipped some of my steps as well - like the step that caused the table to have precisely 128 blocks!


I had 128 blocks.
I flushed the buffer cache (you can offline/online the tablespace or stop/start the database)
I read every other block into the cache via the index.
then, we turned on trace and full scanned.

The grep on the tracefile would show how many physical IO's we did.

dbmrc

mal, May 15, 2006 - 6:18 pm UTC

Why can't we stick to formula
max_io_size=db_block_size*dbmrc

Tom Kyte
May 15, 2006 - 6:32 pm UTC

You may do whatever you wish to do.

You asked me what I would suggest, and I will keep suggesting what I suggested.

parag jayant patankar, May 16, 2006 - 7:50 am UTC

Hi Tom,

Mr Conor and you said
<
A practical alternative to get both maximum tablescan performance without biasing the optimizer toward full scans is to set db_file_multiblock_read_count to 128, and set MBRC (via dbms_stats) to (say) 8, along with the other system stats.
>
< Tom >
< intresting, very nice >

I have not understood, that if you had collected system statistics which will show you MBRC, then why to set MBRC to 8 or 16 ..etc ? MBRC should be set exactly as per system statistics !!! Am I correct, if not kindly explain idea behind this.

thanks & regards
pjp



Tom Kyte
May 16, 2006 - 8:39 am UTC

the optimizer will use the observed multi-block read count as reported in the system statistics to cost out the query, but the database will use the db_file_multiblock_read count to actually do the IO's

thus, you can have the optimizer use the value to cost that is most appropriate for your system AND when we go to do the IO actually use the maximum IO size for your system.

system stats,

A reader, May 16, 2006 - 9:52 am UTC

How often do you recommend to run dbms_stats.gather_system_stats right?

I observed all the parameters in gather_system_stats have default values. Is there any parameter that we have to change while gathering system statistics?

Where would the statistics gets stored?
How do you know when was the system statistics collected?

Thanks,


Tom Kyte
May 16, 2006 - 9:59 am UTC

generally, you would only need to do it again after a "big change". It measures your observed multi-block read count, you single and multi block IO speeds and cpu speed.

You would override default parameters on an "as needed basis", there are none you HAVE to change, as with all things - there are some you might want to for whatever reason.

The statistics are stored in the data dictionary - sys.aux_stats$ - or in a statistics table of your choosing (but they are only used when in aux_stats$, you can use dbms_stats to move them in and out of that table). The time of collection is stored there as well.

db_file_multiblock_read_count at session level

A reader, July 18, 2007 - 1:44 pm UTC

I have query which runs fast by setting db_file_multiblock_read_count at session level to 512 and then setting it back to 64( the original setting )

alter session set db_file_multiblock_read_count=512;
run the query .....
alter session set db_file_multiblock_read_count=64;

There are some external consulatants doing oracle consultancy for my company and they are of the openion that setting db_file_multiblock_read_count at session level to 512 confuses the oracle optimizer and it shouuld not be set more that 64.
What is your opinion.

Thanks & regards

Tom Kyte
July 18, 2007 - 2:24 pm UTC

why do you want an opinion? wouldn't you rather have fact?

Depending on the OS - the true multi-block read count varies. Many times, the largest IO we can do is 1MB - meaning with an 8k block size - the multiblock read count max is really 128 blocks.

In most all cases, it will be larger than 64 - by setting really high, you've basically maxed out your multiblock read count.

It does not "confuse" the optimizer to change it - it changes the way the optimizer will cost the full scan when developing a query plan (it could well be that by you setting it higher, Oracle stopped using an inefficient index access and started full scanning to get better performance).

The optimizer does not get confused here, it simply uses a reduced cost and the execution of the SQL will use this larger IO read size if possible. That is the net effect of all of this.

here is some more information from my book Effective Oracle by Design:

<quote>

The DB_FILE_MULTIBLOCK_READ_COUNT parameter controls the number of blocks Oracle will read in a single I/O while doing a full scan or an index fast-full scan. The higher this value, the lower the cost of a full scan.
Consider the following example:

big_table@ORA920> show parameter db_file_multi

NAME                             TYPE        VALUE
-------------------------------- ----------- --------------------
db_file_multiblock_read_count    integer     16
 
big_table@ORA920> set autotrace traceonly explain
big_table@ORA920> select * from big_table;
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE 
          (Cost=2136 Card=1833857 Bytes=154043988)
   1    0   TABLE ACCESS (FULL) OF 'BIG_TABLE' 
            (Cost=2136 Card=1833857 Bytes=154043988)

big_table@ORA920> alter session set db_file_multiblock_read_count = 32;
Session altered.

big_table@ORA920> select * from big_table;
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE 
          (Cost=1354 Card=1833857 Bytes=154043988)
   1    0   TABLE ACCESS (FULL) OF 'BIG_TABLE' 
            (Cost=1354 Card=1833857 Bytes=154043988)

big_table@ORA920> alter session set db_file_multiblock_read_count = 64;
Session altered.

big_table@ORA920> select * from big_table;
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE 
          (Cost=858 Card=1833857 Bytes=154043988)
   1    0   TABLE ACCESS (FULL) OF 'BIG_TABLE' 
            (Cost=858 Card=1833857 Bytes=154043988)


As you can see, the higher DB_FILE_MULTIBLOCK_READ_COUNT is set, the lower the cost of a full scan. A full scan will become more appealing than an index access. This will bias a full scan over indexes as it increases.

The valid range of values for DB_FILE_MULTIBLOCK_READ_COUNT is highly operating system-dependent. Each operating system will have its true maximum on the size of an I/O. In this example, when we set our read count to 64, that was 64 ¿ 8KB, or 0.5MB per I/O that we were requesting. Is our operating system able to accommodate that? We can consult our operating system tuning guide to find the maximum read size, or we can trick Oracle into giving us that information. To get the information from Oracle, we enable tracing like this (to capture wait events into the trace file) and set our DB_FILE_MULTIBLOCK_READ_COUNT very high:
big_table@ORA920> alter session set events 
  2 '10046 trace name context forever, level 12';
Session altered.

big_table@ORA920> alter session set db_file_multiblock_read_count = 5000000;
Session altered.

Then we run a query that does a full scan, such as select /*+ noparallel(big_table) full(big_table) */ * from big_table. We¿ll undoubtedly see wait events on I/O, namely db file scattered read wait events. Using the Unix utility grep to scan the trace file we generated, we find this:

$ grep scattered ora920_ora_31266.trc | more
WAIT #3: nam='db file scattered read' ela= 61870 p1=9 p2=33035 p3=126
WAIT #3: nam='db file scattered read' ela= 48985 p1=9 p2=33547 p3=126
WAIT #3: nam='db file scattered read' ela= 55994 p1=9 p2=33931 p3=126
WAIT #3: nam='db file scattered read' ela= 44090 p1=9 p2=34187 p3=126
WAIT #3: nam='db file scattered read' ela= 46638 p1=9 p2=34699 p3=126
WAIT #3: nam='db file scattered read' ela= 43463 p1=9 p2=35339 p3=126
WAIT #3: nam='db file scattered read' ela= 98053 p1=9 p2=35851 p3=126
WAIT #3: nam='db file scattered read' ela= 46462 p1=9 p2=36363 p3=126


The Oracle9i Database Reference Guide explains what the p1, p2, and p3 values represent, and it tells us p3 is the number of blocks we are requesting to read at one time. Apparently, on this operating system (Red Hat Linux), we can read just short of 1MB of data at a time. (On a Sun Solaris system, my maximum I/O size was 64 blocks, or 0.5MB, at a time.)


On a DSS or data warehouse system, you would want this set to the maximum I/O size your system permits. Not only does it affect query-plan generation, affecting the cost of a full-scan operation, but it also directly affects the performance of the query. The fewer I/O calls to the operating system, the faster a full scan will perform.

On a transactional system, where you do not anticipate doing full scans frequently, a smaller setting may be appropriate, to make full scans less appealing in those systems. You can always use the ALTER SESSION command in any batch jobs to permit them to use a larger multi-block read count.
In Oracle9i, with support for multiple block size databases, it is interesting to note that this parameter is actually used to set the IO size, not the number of blocks read! What that means is that Oracle will take your db_file_multiblock_read_count and multiply that by your default blocksize (the blocksize of your SYSTEM tablespace). That is what Oracle will use as the IO size on your system. If your default block size is 8k and you set this parameter to 16, you will only read 8 blocks at a time in a 16k blocksize tablespace. This fact is not documented and was learned only by testing. In response to a recent AskTom question:

I have a 32K blocksize tablespace on a database where the "default" block size is 8K. Does the db_file_multiblock_read_count apply as a multiple of the 8K for all datafiles, or is it tablespace dependant -- ie. (32K*dfmrc) for 32K tablespace?, and (8K*dmfrc) for 8K tablespaces's on the same instance?
It was an interesting question so I setup a simulation to test with. I was using an 8k blocksize database by default and simply created a 16k tablespace to test with. In order to do this, I had to setup my 16k cache size first, I did that by sizing down my db_cache_size and then setting the db_16k_cache_size and creating a tablespace:
ops$tkyte@ORA920> show parameter db_cache_size;

NAME                                 TYPE        VALUE
db_cache_size                        big integer 67108864
ops$tkyte@ORA920> alter system set db_cache_size=32m;
System altered.

ops$tkyte@ORA920> alter system set db_16k_cache_size=32m;
System altered.

ops$tkyte@ORA920> create tablespace sixteen_k
  2  blocksize 16k
  3  extent management local
  4  uniform size 2m
  5  /
Tablespace created.
Then, I simply copied the BIG_TABLE into that tablespace:
ops$tkyte@ORA920> create table big_table_copy_16k
  2  TABLESPACE sixteen_k
  3  as
  4  select * from big_table.big_table;
Table created.

ops$tkyte@ORA920> analyze table big_table_copy_16k  
  2 compute statistics for table;
Table analyzed.


Using the same technique outlined above, setting the 10046 EVENT and inspecting the trace file after executing:
ops$tkyte@ORA920> select /*+ noparallel(b) full(b) */ count(*) 
  2 from big_table_copy_16k b;

  COUNT(*)
----------
   1833792

ops$tkyte@ORA920> select /*+ noparallel(b) full(b) */ count(*) 
  2 from big_table.big_table b;

  COUNT(*)
----------
   1833792


and upon inspecting the trace file, we discover:
select /*+ noparallel(b) full(b) */ count(*)
  from big_table_copy_16k b
END OF STMT
PARSE #1:c=1953,e=1728,p=1,cr=1,cu=0,mis=1,r=0,dep=0,og=4, 
BINDS #1:
EXEC #1:c=0,e=132,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4, 
WAIT #1: nam='SQL*Net message to client' ela= 6 p1=1650815232 p2=1 p3=0
WAIT #1: nam='db file scattered read' ela= 88910 p1=13 p2=6 p3=8
WAIT #1: nam='db file scattered read' ela= 662 p1=13 p2=14 p3=8
WAIT #1: nam='db file scattered read' ela= 869 p1=13 p2=22 p3=8

(repeated continuously)
 select /*+ noparallel(b) full(b) */ count(*)
  from big_table.big_table b
END OF STMT
PARSE #1:c=1953,e=1350,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=4, 
BINDS #1:
EXEC #1:c=0,e=124,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4, 
WAIT #1: nam='db file scattered read' ela= 500 p1=9 p2=33035 p3=16
WAIT #1: nam='db file scattered read' ela= 501 p1=9 p2=33051 p3=16
WAIT #1: nam='db file scattered read' ela= 566 p1=9 p2=33067 p3=16

Now, my multi-block read count in this case was 16. When we queried the original BIG_TABLE that was in my default block size tablespace ¿ we achieve a multi-block read count of 16 blocks at a time. The BIG_TABLE_COPY in the 16k blocksize tablespace was read 8 blocks at a time ¿ same size reads, just different block counts. Further, if you re-run the example but use a 4k blocksize tablespace ¿ you will discover:
select /*+ noparallel(b) full(b) */ count(*)
  from big_table_copy_4k b
END OF STMT
PARSE #1:c=1953,e=1781,p=1,cr=1,cu=0,mis=1,r=0,dep=0,og=4, 
BINDS #1:
EXEC #1:c=0,e=130,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4, 
 WAIT #1: nam='db file scattered read' ela= 210816 p1=13 p2=18 p3=32
WAIT #1: nam='db file scattered read' ela= 26353 p1=13 p2=50 p3=32
WAIT #1: nam='db file scattered read' ela= 1145 p1=13 p2=82 p3=32


The 4k blocksize tablespace was read 32 blocks at a time ¿ showing that Oracle in this case will read 16 (multi-block read count) * 8k = 128k at a time. This has an interesting side effect on the costing of full table scans that you may want to be aware of. Given that we have 3 tables with the same exact data, using an IO size that is identical, and sizes that are very near to each other (each table was within a few megabytes of each other table in size) -- you would expect the cost of a full scan against each to be the same ¿ but in fact:
ops$tkyte@ORA920> set autotrace traceonly explain
ops$tkyte@ORA920> select /*+ noparallel(b) full(b) */ count(*)
  2    from big_table_copy_4k b;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3273 Card=1)

ops$tkyte@ORA920> select /*+ noparallel(b) full(b) */ count(*)
  2    from big_table.big_table b;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2313 Card=1)

ops$tkyte@ORA920> select /*+ noparallel(b) full(b) */ count(*)
  2    from big_table_copy_16k b;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1857 Card=1)

Oracle is costing each query as if it would read radically differing amounts of data! See how the cost apparently decreases as the blocksize increased. This is something to be aware of when using tablespaces with different sized blocks in the same database.
</quote>

higher db_file_MBRC

A reader, July 26, 2007 - 11:06 am UTC

Do you agree if by setting the db_file_multiblock_read_count to 128 and if the IO call brings 128 blocks in one call during a full table table scan, the buffer cache needs 128 consecutive slots to put those blocks in the hash which could be difficult sometimes to get that big slot resulting in buffer busy waits?

In other words, the higher the value of db_file_multiblock_read_count, the higher the chances in the buffer for waiting to get a slot to be placed.

Is this correct?

Tom Kyte
July 27, 2007 - 9:01 am UTC

128 consecutive?

No, not at all.


the wait event for multi-block IO is db_file_scattered_read - the scattered in there is in reference to the fact that the blocks must be scattered throughout the buffer cache.

We take the DBA (data block address) and hash it to find the list it belongs on, it is unlikely all 128 would end up together in the cache.


That said, if you have 128 blocks to put in the cache - and there are not 128 blocks - then yes, you might have to wait.

That would be highly unlikely to be a bottleneck however - that a full scan with a mere 128 blocks at a time would be worse off than one with 16 for example (as far as getting space in the buffer cache is concerned)

not setting db_file_multiblock_read_count in 10g

raoul, August 24, 2007 - 8:36 am UTC

Hi Tom,

I did create a table named big_table with 857k rows on a 10.2.0.3 Database.
We did not set db_file_multiblock_read_count as suggested from Oracle. So Oracle sets the parameter, right?

cdba@DWTST> show parameter db_file

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_file_multiblock_read_count        integer     72  

cdba@DWTST> select count(*) from big_table;

  COUNT(*)
----------
    857067


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=30179 Card=1)
   1    0   SORT (AGGREGATE)
   2    1     TABLE ACCESS (FULL) OF 'BIG_TABLE' (TABLE) (Cost=30179 Card=805880)



cdba@DWTST.GLOBAL.PARTNERRE.NET> alter session set db_file_multiblock_read_count=16;

Session altered.


cdba@DWTST> select count(*) from big_table;

  COUNT(*)
----------
    857067


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=24480 Card=1)
   1    0   SORT (AGGREGATE)
   2    1     TABLE ACCESS (FULL) OF 'BIG_TABLE' (TABLE) (Cost=24480 Card=805880)


cdba@DWTST> alter session set db_file_multiblock_read_count=72;

Session altered.


cdba@DWTST> select count(*) from big_table;

  COUNT(*)
----------
    857067


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=20048 Card=1)
   1    0   SORT (AGGREGATE)
   2    1     TABLE ACCESS (FULL) OF 'BIG_TABLE' (TABLE) (Cost=20048 Card=805880)

As you can see Oracle sets dbfmrc to 72, but the cost of the FTS with dbfmrc set by oracle is different as when I set dbfmrc manually to 72.

Do you know what exactly happens? Did the influence of dbfmr on costing change in 10g?

Thanks in advance,
Raoul


db_file_multiblock_read_count

Deepak, August 24, 2007 - 1:05 pm UTC

Hi Tom,

Your followups in the current thread are really very helpful. I still have few doubts. Hope you will clear them.

I have a DB which runs on mixed load i.e., OLTP & DSS. We have few big tables which require FTS for reporting and other relatively smaller tables need indexed access. Our DB block size is 8K.

My queries are:

1> If I set db_file_multiblock_read_count=128 (MAX_IO_SIZE=1M) then the optimizer may choose FTS for the other queries as well. Can I set optimizer_index_cost_adj=10 to influence/override the FTS decission?

2> Is it a good idea to set db_file_multiblock_read_count=128 at the session level wherever FTS is required?

3> Will the system statistics override the db_file_multiblock_read_count settings?

Please help me on this.
Tom Kyte
August 27, 2007 - 3:50 pm UTC

1) it is highly doubtful that this will impact a true OLTP system since the number of rows they retrieve are very small. If you have extended OLTP to be "well, they run reports that need first rows optimization for online viewing" - then I would say "first rows optimization"


Or, in 10g, use system statistics and self tuning multi-block read counts. We'll max out the IO size, but use REAL OBSERVED multi-block read counts on your system to cost it out.

2) or you can do that, but in 10g, stop doing that.

3) in 9i, no, in 10g, you don't want to set the multiblock read count, just use system statistics.

db_MBRC and system statistics

AMIR RIAZ, August 29, 2007 - 2:37 pm UTC

Hi tom

in oracle 10g setting both the db_file_multiblock_read_count(to a high value say 128) and also gather system statistics for MBRC(we get value 8 say) sound very strange. in your review above you said the system statistics MBRC will be used to calculate the cost of query and db_file_Multiblock_read_count will be used for performing IO(i.e multi block read) Why the value of system statistics MBRC will not be used for performing IO. this value should over ride the value of db_file_multiblock_read_count otherwise the exact value of MBRC(which will be of system statistics) will not be used and with bigger IO(due to manual setting of db_file_multiblock_read_count) we can overload the IO system.

regards
Amir Riaz
Tom Kyte
September 04, 2007 - 4:18 pm UTC

the value reported in system statistics is the OBSERVED TYPICAL VALUE. We use that to cost out.

however, that also means that sometimes we read MORE, sometimes LESS than that on each read (the read count was set to 128 - on average - ON AVERAGE - we really only achieved 8 blocks in a read call, sometimes we only did 1 block, sometimes we did 128 blocks).


So, we use the observed value to cost out

And we use the set value to do the IO - hoping that we can actually do better than the observed value from time to time.

I fail to see how that would "overload" the IO system - you have 1,000,000 blocks to read - whether you do it 8 at a time, or 128 at a time. You have to do the same number of transfers.


If you do think it would "overload" it, then force it lower - you control it after all.

db_multiblock_read_count and LMT

AMIR RIAZ, September 07, 2007 - 12:22 am UTC

hi tom thanks for the help

recently in our warehouse enviroments we have db_file_multiblock_read_count =128. We have LMT with assm. After knowing the LMT with uniform size can be good for warehouse enviroments i changed all the tablespace to uniform size using the formula db_block_size * db_multiblock_read_count +64K. My objective was to read the whole extent during full scan. Another theory i have is LMT with assm is good for oltp because of few full scan while LMT with uniform size is good for warehouse environment. The reason is LMT with assm can have small extents starting from 64k so we need more multiple read while performing full scan. with large uniform extents the whole big extent will be read in one IO. Do you think i am right in this theory.

regards
Amir riaz

db_file_multiblock_read_count example from effective oracle by design

Yoav, February 15, 2008 - 3:23 pm UTC

Hi Tom,
I runned the example in page 322, against oracle 10.2.0.3 on linux machine.

>ALTER SESSION SET events '10046 trace name context forever, level 12';

Session altered.

> alter session set db_file_multiblock_read_count=500000;

Session altered.

> select /*+ noparallel(big_table) full(big_table) */ * from big_table;

>ALTER SESSION SET EVENTS '10046 trace name context off';
Session altered.

>exit

/software/oracle/admin/prod/udump >grep scattered prod_ora_366.trc | more
/software/oracle/admin/prod/udump >

Nothing found.

/software/oracle/admin/prod/udump >tkprof prod_ora_366.trc tk1.prf

vi tk1.prf
select /*+ noparallel(big_table) full(big_table) */ * 
from  big_table


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     3397      0.29       0.30          0       3570          0       50935
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total     3399      0.29       0.30          0       3570          0       50935

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

Rows     Row Source Operation
-------  ---------------------------------------------------
  50935  TABLE ACCESS FULL BIG_TABLE (cr=3570 pr=0 pw=0 time=102130 us)

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

Can you please explain why i cant see the event 'df file scattered read' in the trace file ?
There are onlt two events:
nam='SQL*Net message from client' and nam='SQL*Net message to client'

Thank You.


Tom Kyte
February 17, 2008 - 7:36 am UTC

.. 50935 TABLE ACCESS FULL BIG_TABLE (cr=3570 pr=0 pw=0 time=102130 us) ...

pr=0, you read everything from the cache.

Why not read exactly MBRC blocks when sweeping a segment?

A reader, June 02, 2009 - 12:15 pm UTC

Instead of splitting a large multiblock read for skipping already cached blocks, why don't the shadows do something like this:

- Read MBRC blocks (no less) into a temporary buffer, say into the PGA
- Copy the blocks into the buffer cache, skipping any blocks already there

That way Oracle would always use the max I/O size you configure, resulting in less I/O calls. You would have the overhead of moving the blocks you need from RAM to RAM, but that's much quicker than I/O.
Tom Kyte
June 02, 2009 - 6:39 pm UTC

because the multiblock read is designed to read into the buffer cache - that is the way it works (now).

DW queries and full table scan

A reader, May 21, 2010 - 10:31 am UTC

Hello Tom

Please find the summary of AWR report for a DW,it shows that db file scattered read is the wait which is taking maximum time, to reduce the time taken by queries (60% 0r so doing full table scans) we tried mutli block read count as 128..but what we have seen that when we increased it to 128 from 8 - the Logical IO's have increased cosiderably for the segments whic are being Full scanned.

can you explain us - why it has happened...is it something expected.

Thanks
Tom Kyte
May 24, 2010 - 12:42 pm UTC

if you have AWR, you have 10g or above.

If you have 10g or above, you should not ever set db file multiblock read count - we set it internally

we COST the query with the actual observed multiblock read count.
we RUN the query using the maximum IO size on your system.


In any case, when you change a parameter like that, you can cause plans to change. When plans change - their IO patterns change. So, I suspect you caused plans to change and those plans were not changed for the better.

Suggestion: unset - remove entirely - db_file_multiblock_read_count in 10g and above.

systems

A reader, May 25, 2010 - 2:11 am UTC

Thanks Tom,

a concidence, I was reading the same thing in oracle 10g PT guide as well. where they say that we should not set db file multiblock read count at all.

one question - will gathering the systme stats would help as I can see that system stat is not gatherd in this databse.

Thanks.
Tom Kyte
May 25, 2010 - 7:31 am UTC

gathering system statistics would affect query plans, so doing that will help if and only if

a) plans do in fact change after you gather
b) they change for the better


It could easily be a case of "you have reset your expectations" - or get into the logic and change the way the applications interacts with the database (fix your algorithms)

relevance of db_file_multiblock_read_count setting

Ravi B, February 02, 2017 - 6:57 pm UTC

Hello Team,

Assuming IO capability is limited to SSTIOMAX set by Oracle (1MB or 128 blocks) and IO is mostly OS dependent. If Oracle internally sets SSTIOMAX what is the point in increasing db_file_multiblock_read_count to say 500 or 1000 for DSS systems.

Pardon my ignorance but could you please let us know how SSTIOMAX, db_file_multiblock_read_count, buffer cache are tied together when we are talking about FTS on big tables from Data warehouses like 100GB or more? How to correctly come up with the numbers?
Connor McDonald
February 03, 2017 - 7:27 pm UTC

I've never seen any significant performance difference from a dbfmbrc set more than 128.

People often think that IO is the key for reading data, but generally for (modern) storage, the key is having sufficient CPU power to digest all of that data. So even reading 1 megabyte per read, at (say) 100 IOPS per disk, times 100 disks...is already at 10 GB (bytes not bits) per second. You need a good chunk of CPU to handle that amount of data coming in.

So worry less about parameters.

relevance of db_file_multiblock_read_count setting

Ravi B, February 03, 2017 - 7:42 pm UTC

Thanks for your response. Not sure how relevant is this information in year 2017.

https://blog.art-of-coding.eu/dramatic-effect-of-mbrc/

I have an INSERT where it joins a 15GB table joined with few other smaller tables (DW/ETL related). FTS on this big table takes about 12 minutes when i monitor the session from v$session_longops. Yes true, i dint see *much* difference setting the value more than 128.
Connor McDonald
February 03, 2017 - 7:48 pm UTC

One thing that is relevant from the post is the recommendation to do some measurement to get a good idea of what is best for the particular platform/server/storage etc.

Welcome back Tom

Yogesh, February 04, 2017 - 1:34 am UTC

Good to see you replying after long gap - Aug 2015?

Connor McDonald
February 06, 2017 - 2:52 pm UTC

Click on the About section on AskTom.

Times have changed :-)