The tests show that all the disk I/O's are costed by the Optimizer as single block disk I/O's. I say this because I changed the cost of multi-block disk I/O's and the cost reported for the Hash Join operation itself did not change. Hence it must be costed as single block disk I/O's by the Optimizer.
The tests I was doing were a join between two tables that used a Hash Join in the execution plan (see previous post for the SQL used in this query). The key points are:
- The two source tables are accessed by Full Table Scans (TABLE ACCESS FULL) in the execution plan
- These feed into a HASH JOIN operation
- Which in turn feeds into a final operation - a SORT AGGREGATE for the SUM's in the SELECT output
- By adding together the costs of the source data accesses and subtracting from the total cost reported for the Hash Join, we get the net cost of the Hash Join operation itself
In my Oracle 12 instance (12.1.0.2.0) I only have the "No Workload" default system statistics set in the database, which is the minimal set of statistics. This provides values for the following:
IOSEEKTIM
- Time in milliseconds for a disk to move the read / write head to the track you want to access - default value of 10IOTFRSPEED
- Bytes transferred per millisecond once a transfer starts - default value of 4096MBRC
- Multi-block read count in blocks achieved on average - default value of 8CPUSPEEDNW
- Speed of CPU in units of millions of cycles per second (not relevant here)
MBRC
here is not the same as the initialization parameter db_file_multiblock_read_count
, even though their definitions seem to be the same. This MBRC
is not set from the initialization parameter, and remains the same
within the system statistics until explicitly changed (one way or
another). MBRC
is intended to represent the actual size of
multi-block reads that were achieved on your computer system, and is
set when Workload statistics are collected or when set manually.The Optimizer uses these minimal system statistics to derive the values for the elapsed times for single and multi-block reads (
SREADTIM
and MREADTIM
respectively). The formulae it
uses are:SREADTIM = IOSEEKTIM + (DB_BLOCK_SIZE / IOTFRSPEED) MREADTIM = IOSEEKTIM + (MBRC * DB_BLOCK_SIZE / IOTFRSPEED)With the default values for System Statistics as stated, and a database block size of 8192 (8 KB) this gives values of
SREADTIM
= 12 ms, MREADTIM
= 26 ms.What this really means for the Optimizer is that a multi-block read takes 26 / 12 = 2.167 times longer than a single block read i.e. its "cost" is 2.167 times that of a single block read. This is used by the Optimizer when costing multi-block read based operations - it "converts" the multi-block read time into an equivalent number of single block read operations, which all have a cost unit of 1 and are the basis for how the Optimizer reports and compares execution plan costs.
If I were to increase the
MBRC
from 8 to 16, then the MREADTIM
would increase to 42 ms, and a cost factor of 42 / 12 = 3.5 times that
of a single block read. The relative net cost though would actually
decrease, because each multi-block read would now be reading 16 blocks
in one disk I/O rather than 8 blocks i.e. half the number of disk reads
are needed to read the same number of blocks in from disk, at a relative
cost ratio of 1.615 (3.5 / 2.167). So the decrease in the number of
disk reads is greater than the relative increase in cost per disk read.If the Hash Join operation involved multi-block disk reads then changing
MBRC
would change the relative cost of those disk reads and we would see a
change in the net cost of the Hash Join as reported in the execution
plan.I changed the value of
MBRC
manually and then shutdown and restarted the database:exec dbms_stats.set_system_stats ('MBRC', 16) shutdown immediate startupThis was to ensure that nothing was still present in memory in the SGA - neither any existing execution plans, or any system statistics used to cost those execution plans.
When I ran the same test queries again, the total costs decreased because the source data accesses are full table scans which use multi-block reads i.e. this was expected, and so the total cost reported at the Hash Join step decreased. However, when the costs of the source data accesses were subtracted from the total cost after the Hash Join step, the net cost of the Hash Join operation itself was exactly the same as it was before for the same query.
Likewise when I increased the
MBRC
value to 32 there was no change in the net cost of the Hash Join operation when it overflowed to disk.The conclusion then is that no multi-block disk reads are used within the costing of the Hash Join operation by the Optimizer when the hash table it uses overflows to disk.
Which means that the formula I posted before for an overflowing Hash Join cost is not dependent on multi-block reads at all:-
- ( ((Build Columns Size + 12) * Build Row Count) + ((Probe Columns Size + 12) * Probe Row Count) ) * 0.0475
No comments:
Post a Comment