Create Table Creating Dirty Buffers….

I always thought that the creation of table is a mere data dictionary update. I mean to say that the data dictionary , dba_tables, OBJ$ and other similar ones would get updated when we create a table. The logic was that its just a definition so where else it would be going? Its correct too that its just a definition but still for couple of things, Oracle does access DataBuffer Cache too when it creates a table and (here is what I didnt even think to see) not just accesses it but also makes couple of its block dirty too. Doesn’t make a sense,well ok let the numbers,bits, flags speak then. Have a look,


    1. SQL*Plus: Release – Production on Fri Aug 22 00:24:26 2008  
    3. Copyright (c) 19822007, Oracle.  All rights reserved.  
    5. Enter password:  
    7. Connected to:  
    8. Oracle Database 11g Enterprise Edition Release – Production  
    9. With the Partitioning, Oracle Label Security, OLAP, Data Mining,  
    10. Oracle Database Vault and Real Application Testing options  
    12. SQL> create table t (a number);  
    14. Table created.  
    16. SQL> select object_id ,object_name from user_objects where object_name=‘T’;  
    19. ———-  ———-  
    21.      72217  T  

    Here comes the interesting part:
    1. SQL> SELECT b.block#,b.class#,b.status, object_name, object_type, dirty “Dirty” FROM v$bh b,  
    2.   2   dba_objects o WHERE b.objd = o.data_object_id AND o.owner = ‘AMAN’ and object_name=‘T’;  
    4.     BLOCK#     CLASS# STATUS     OBJECT_NAME          OBJECT_TYPE         D  
    5. ———- ———- ———- ——————– ——————- –  
    6.       3746          9 xcur       T                    TABLE               Y  
    7.       3745          8 xcur       T                    TABLE               Y  
    8.       3747          4 xcur       T                    TABLE               Y  
    10. SQL>  

    The buffers from the table T are marked Dirty and are accessed in the XCUR mode which means the blocks are accessed in the Exclusive Current mode and is representing that these blocks are going to be modified. The description of the buffer status which is shown from V$BH(or X$BH.status) from 11gr1 docs is given here,

    STATUS VARCHAR2(6) Status of the buffer: 

    • free – Not currently in use
    • xcur – Exclusive
    • scur – Shared current
    • cr – Consistent read
    • read – Being read from disk
    • mrec – In media recovery mode
    • irec – In instance recovery mode

    Here is the link for the same in docs.

    A much better description of the same is mentioned in the 9iR2 docs,in the RAC guide. The link is mentioned below and also the description,

    Block Access Modes and Buffer States

    An additional concurrency control concept is the buffer state which is the state of a buffer in the local cache of an instance. The buffer state of a block relates to the access mode of the block. For example, if a buffer state is exclusive current (XCUR), an instance owns the resource in exclusive mode.

    To see a buffer’s state, query the STATUS column of the V$BH dynamic performance view. The V$BH view provides information about the block access mode and their buffer state names as follows:

    • With a block access mode of NULL the buffer state name is CR–An instance can perform a consistent read of the block. That is, if the instance holds an older version of the data.
    • With a block access mode of S the buffer state name is SCUR–An instance has shared access to the block and can only perform reads.
    • With a block access mode of X the buffer state name is XCUR–An instance has exclusive access to the block and can modify it.
    • With a block access mode of NULL the buffer state name is PI–An instance has made changes to the block but retains copies of it as past images to record its state before changes.

    Only the SCUR and PI buffer states are Real Application Clusters-specific. There can be only one copy of any one block buffered in the XCUR state in the cluster database at any time. To perform modifications on a block, a process must assign an XCUR buffer state to the buffer containing the data block.

    For example, if another instance requests read access to the most current version of the same block, then Oracle changes the access mode from exclusive to shared, sends a current read version of the block to the requesting instance, and keeps a PI buffer if the buffer contained a dirty block.

    At this point, the first instance has the current block and the requesting instance also has the current block in shared mode. Therefore, the role of the resource becomes global. There can be multiple shared current (SCUR) versions of this block cached throughout the cluster database at any time.

    So the blocks are meant for the modification and hence they are marked dirty after being modified. The same is confirmed from the query written by Jonathan Lewis,

    1. SQL> select  
    2.          decode(bitand(flag,power(2,00)),0,‘No’,‘Yes’ ) buffer_dirty,  
    3.          decode(bitand(flag,power(2,01)),0,‘No’,‘Yes’ ) about_to_modify,  
    4.          decode(bitand(flag,power(2,02)),0,‘No’,‘Yes’ ) mod_started,  
    5.          decode(bitand(flag,power(2,03)),0,‘No’,‘Yes’ ) block_has_been_logged,  
    6.          decode(bitand(flag,power(2,04)),0,‘No’,‘Yes’ ) temp_data,  
    7.          decode(bitand(flag,power(2,05)),0,‘No’,‘Yes’ ) being_written,  
    8.          decode(bitand(flag,power(2,06)),0,‘No’,‘Yes’ ) waiting_for_write,  
    9.          decode(bitand(flag,power(2,07)),0,‘No’,‘Yes’ ) checkpoint_wanted,  
    10.          decode(bitand(flag,power(2,08)),0,‘No’,‘Yes’ ) recovery_reading,  
    11.          decode(bitand(flag,power(2,09)),0,‘No’,‘Yes’ ) unlink_from_lock,  
    12.          decode(bitand(flag,power(2,10)),0,‘No’,‘Yes’ ) down_grade_lock,  
    13.          decode(bitand(flag,power(2,11)),0,‘No’,‘Yes’ ) cross_instance_write,  
    14.          decode(bitand(flag,power(2,12)),0,‘No’,‘Yes’ ) reading_as_CR,  
    15.          decode(bitand(flag,power(2,13)),0,‘No’,‘Yes’ ) gotten_in_current_mode,  
    16.          decode(bitand(flag,power(2,14)),0,‘No’,‘Yes’ ) stale,  
    17.          decode(bitand(flag,power(2,15)),0,‘No’,‘Yes’ ) deferred_ping,  
    18.          decode(bitand(flag,power(2,16)),0,‘No’,‘Yes’ ) direct_access,  
    19.          decode(bitand(flag,power(2,17)),0,‘No’,‘Yes’ ) moved_to_lru_tail,  
    20.          decode(bitand(flag,power(2,18)),0,‘No’,‘Yes’ ) ignore_redo,  
    21.          decode(bitand(flag,power(2,19)),0,‘No’,‘Yes’ ) only_sequential_access,  
    22.          decode(bitand(flag,power(2,20)),0,‘No’,‘Yes’ ) unused_0x100000,  
    23.          decode(bitand(flag,power(2,21)),0,‘No’,‘Yes’ ) re_write_needed,  
    24.          decode(bitand(flag,power(2,22)),0,‘No’,‘Yes’ ) flushed,  
    25.          decode(bitand(flag,power(2,23)),0,‘No’,‘Yes’ ) resilvered_already,  
    26.          decode(bitand(flag,power(2,24)),0,‘No’,‘Yes’ ) ckpt_writing,  
    27.          decode(bitand(flag,power(2,25)),0,‘No’,‘Yes’ ) redo_since_read,  
    28.          decode(bitand(flag,power(2,26)),0,‘No’,‘Yes’ ) unused_0x4000000,  
    29.          decode(bitand(flag,power(2,27)),0,‘No’,‘Yes’ ) unused_0x8000000,  
    30.          decode(bitand(flag,power(2,28)),0,‘No’,‘Yes’ ) unused_0x10000000,  
    31.          decode(bitand(flag,power(2,29)),0,‘No’,‘Yes’ ) unused_0x20000000,  
    32.          decode(bitand(flag,power(2,30)),0,‘No’,‘Yes’ ) unused_0x40000000,  
    33.          decode(bitand(flag,power(2,31)),0,‘No’,‘Yes’ ) unused_0x80000000  
    34.  from x$bh where obj=72217;  
    37. — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —  
    38. Yes No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  Yes No  No  No  No  No  No  
    40. Yes No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  Yes No  No  No  No  No  No  
    42. Yes No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  No  Yes No  No  No  No  No  No  

    So indeed the buffers are marked are as dirty only. But the buffers are supposed to be marked dirty when they are changed and with the create table,what’s going on which has made them change. Each buffer belongs to a particular classLets try to find out the class description of these buffers using their numbers.The block classes are described here*,

    Block Class Description
    1 Data block
    2 Sort block
    3 Save undo block
    4 Segment header
    5 Save undo header
    6 Free list
    7 Extent map
    8 1st level bitmap block
    9 2nd level bitmap block
    10 3rd level bitmap block
    11 Bitmap block
    12 Bitmap index block
    13 File header block
    14 Unused
    15 System undo block
    16 System undo block
    17 Undo header
    18 Undo block

    So according to the result that we have got, the blocks belong to the classes 4,8,9 and these numbers represent the classes(in the same order ),Header Block,1st level Bitmap Block,2nd Level Bitmap Block.

    When oracle creates a table, it has to allocate a segment header block. This is done by picking up a block from a cache,formatting it,writing into it the new description of the data segment.As it is written so it is marked dirty and subsequently is written to the datafile.

    The Automatic Segment Space Management allocates 3 levels of the blocks for example, Level1 , Level2 , Level3. The level 3 is the bitmap header block which resides in the segment header. This is linked to the Level 2 block. This block is used to search Level 1 which is always the first block in the extent. Level 1 marks the blocks for their respective status. So it appears , Oracle does the same what it does for the Segment header block to the Bitmap Blocks i.e. acquires two blocks from the cache , marks as Bitmap blocks, writes into them and marks them dirty. So this is the reason that we get the blocks marked as dirty even when we have not done anything by ourselves to change them. For me it was a new concept as I was not aware about it before. I would still try to dig upon more and will try to post more as and when I shall find it out. Heartiest thanks to Jonathan Lewis for helping me to understand it.