Oracle Scratchpad

July 24, 2009

IQ2 – Answers

Filed under: Index Explosion,Indexing,Infrastructure,trace files,Troubleshooting — Jonathan Lewis @ 9:04 pm BST Jul 24,2009

I was planning to supply the answers to Index Quiz 2 as a comment – but there’s a lot of block dumps involved, and it’s easier to do that in postings.

Question 1: I’ve created a table and index with initrans 4, then inserted one row into the table. How many ITL (interested transaction list – see glossary) entries will there be in the first block of the index when you dump it.

Answer 1: The table block will show 4 entries in the ITL, obeying your setting for initrans, but the index block will show only two entries – unless you’re using Oracle 8i or earlier (Basically indexes tend to ignore the setting for initrans  except when you rebuild an index, or create it on existing data.):

Block header dump:  0x01400d0a
 Object id on Block? Y
 seg/obj: 0x183e3  csc: 0x00.5528ef6  itc: 2  flg: -  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x02   0x000b.014.00004c37  0x008010b7.0259.1f  --U-    1  fsc 0x0000.05528efe

If you’ve done the index block dump, you’ll notice that the dump is described as a “Leaf Block Dump”. When an index consists of a single block, that block is a leaf block even though the block is also the root block. As the index grows the root block will eventually be reformatted as a “Branch Block”.

Another little difference between indexes and tables when you first create them is that the root block is formatted the moment you create the index. If you dumped the table block before inserting any data you would find that only the segment header block and (if you were using ASSM) the space management bitmap blocks none had been formatted, but the data blocks would still contain whatever garbage was left over from their previous usage.

Question 2: After inserting 300 rows from a single session the root block splits and the index grow to three blocks. What will the ITLs of the root and two leaf blocks look like.

Answer 2: The root block will now be formatted as a branch block, and its ITL will hold a single entry (itc = 1). That’s a feature of branch blocks – end user processes don’t modify them directly, the only thing that changes them is a “service transaction” as they split, or as they acquire new entries as one of their associated leaf blocks splits – so they only need one ITL slot, called the “service ITL”.

Since there is only one “service ITL” in a branch block, if two leaf blocks split at the same time then one of them has to wait for the other to complete and free up the “service ITL”. Although it’s hidden from v$segstat there is a segment statistic (number 13: “service ITL waits”) in x$ksolsstat – the underlying x$ table – that records this event. I believe that this event is also one of the events recorded by the wait called “enq: TX – index contention”.

Block header dump:  0x01400d0a
 Object id on Block? Y
 seg/obj: 0x183e3  csc: 0x00.5529151  itc: 1  flg: -  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x001c.00e.000005b1  0x00802b9d.007c.01  -BU-    1  fsc 0x0000.05529156

The leaf blocks will hold two ITL entries – the “service ITL” and one ITL for end-user transactions.

Block header dump:  0x01400d0b
 Object id on Block? Y
 seg/obj: 0x183e3  csc: 0x00.5529153  itc: 2  flg: -  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x001c.00e.000005b1  0x00802b9e.007c.01  -B--    1  fsc 0x0000.00000000
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

Block header dump:  0x01400d0c
 Object id on Block? Y
 seg/obj: 0x183e3  csc: 0x00.55291ae  itc: 2  flg: O  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x001c.00e.000005b1  0x00802b9e.007c.02  CB--    0  scn 0x0000.05529156
0x02   0x000c.003.0000314c  0x00801a48.012f.36  --U-    1  fsc 0x0000.055291b0

Note that the Flag value for the “service ITL” contains a B in the second place. According to a note published by Steve Adams a few years ago this is to tell us that the undo record reference in the Uba (undo block address) column contains the undo for the ITL entry. I’ve only ever seen this value set in index blocks after a block split – so I’m not sure that this explanation is entirely correct (at least, for more recent versions of Oracle).

Question 3: Recreate the table and index, then use 10 concurrent sessions to insert one row each. Don’t commit until all 10 rows are inserted. Then use another session to insert 300 more rows. What will the ITLs for the three index blocks look like.

Answer 3: Again the root block will be formatted as a branch block, so it will have a single (service) ITL entry. The first dump below is the root block just after inserting the first 10 rows, the second is after the block split:

Block header dump:  0x01400f0a
 Object id on Block? Y
 seg/obj: 0x183e7  csc: 0x00.55292b2  itc: 11  flg: -  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x02   0x0010.023.00000d36  0x00803f2f.0093.0d  --U-    1  fsc 0x0000.05529405
0x03   0x0013.015.00000d1f  0x00802436.00a6.0b  --U-    1  fsc 0x0000.05529409
0x04   0x000e.02c.00000e29  0x008004bd.00c2.03  --U-    1  fsc 0x0000.05529415
0x05   0x0002.02d.0001582c  0x00801d33.2556.07  --U-    1  fsc 0x0000.05529417
0x06   0x0005.001.00013ec3  0x00800eb1.248b.38  --U-    1  fsc 0x0000.05529419
0x07   0x000f.004.00000e2c  0x00802739.009d.2b  --U-    1  fsc 0x0000.0552941d
0x08   0x0019.01f.000005b3  0x008021ae.0055.0f  --U-    1  fsc 0x0000.0552941f
0x09   0x0015.005.00000bf3  0x00800d42.007d.15  --U-    1  fsc 0x0000.05529421
0x0a   0x0008.008.00013ab9  0x00803c47.1d00.35  --U-    1  fsc 0x0000.05529424
0x0b   0x000b.00c.00004c37  0x008010b7.0259.3e  --U-    1  fsc 0x0000.05529412

Block header dump:  0x01400f0a
 Object id on Block? Y
 seg/obj: 0x183e7  csc: 0x00.552960f  itc: 1  flg: -  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0006.019.00011880  0x00800db5.1cfc.01  -BU-    1  fsc 0x0000.05529616

Note that we have 11 entries in the ITL before the split. The first ITL entry of any index block is always reserved for the “service ITL” so that a block split can take place whenever needed. Because we had 10 concurrent transactions changing this leaf block we needed 10 more ITL entries – for a total of 11 – one for each uncommitted transaction.

After the split the root block is reformatted as a branch block – note that the block address (0x01400f0a) has not changed. The root block of an index is always the block after the segment header block, and even a block split doesn’t change that. Since the root block has become a branch block, its ITL count drops back to one.

Look what has happened in the leaf blocks, though:


Block header dump:  0x01400f0b
 Object id on Block? Y
 seg/obj: 0x183e7  csc: 0x00.5529613  itc: 11  flg: -  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0006.019.00011880  0x00800db6.1cfc.01  -B--    1  fsc 0x0000.00000000
0x02   0x0016.00f.00000934  0x008039f6.00a9.1c  ----    1  fsc 0x0000.00000000
0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x04   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x05   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x06   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x07   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x08   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x09   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x0a   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x0b   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

Block header dump:  0x01400f0c
 Object id on Block? Y
 seg/obj: 0x183e7  csc: 0x00.552966c  itc: 11  flg: O  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0006.019.00011880  0x00800db6.1cfc.02  CB--    0  scn 0x0000.05529616
0x02   0x0007.02c.0000fcba  0x00800c7d.1dce.2f  C---    0  scn 0x0000.0552966c
0x03   0x0010.000.00000d37  0x00803f2f.0093.25  --U-    1  fsc 0x0000.0552966d
0x04   0x0012.013.00000e17  0x0080126a.0096.3d  --U-    1  fsc 0x0000.0552966f
0x05   0x0018.02a.000005d0  0x008003f3.0056.16  --U-    1  fsc 0x0000.05529671
0x06   0x0013.024.00000d1f  0x00802436.00a6.1f  --U-    1  fsc 0x0000.05529672
0x07   0x001a.019.000005c6  0x00800b48.005d.2b  --U-    1  fsc 0x0000.05529674
0x08   0x001b.013.000005d6  0x00800ad8.00a0.0e  --U-    1  fsc 0x0000.05529676
0x09   0x000a.01d.000106f1  0x00808d2b.1e45.2d  --U-    1  fsc 0x0000.05529677
0x0a   0x001d.008.000005bc  0x00803ee4.0071.0f  --U-    1  fsc 0x0000.05529679
0x0b   0x0017.004.000005c2  0x00800a83.0075.02  C---    0  scn 0x0000.0552966a

Again we see that Oracle has ignored our setting of initrans. Both leaf blocks have 11 slots in their ITLs, not the four  that we might expect. Whenever a leaf block splits Oracle copies the existing ITL into both the resulting leaf blocks – partly because that makes it easier to deal with read-consistency, and partly because it’s quite possible that a single active transaction could be locking rows in both of the new blocks.

Think about what this means – if you have one brief burst of concurrent activity that pushes the ITL size up in just one block of the index then every block that splits off from that one block (and its “descendents” will have a large ITL – whether it’s going to be needed in future or not… and we’ll examine that thought a little more in a future article.

[Further reading on Index ITL Explosion]

9 Comments »

  1. [...] IQ2 – Answers [...]

    Pingback by Index Quiz 2 « Oracle Scratchpad — July 24, 2009 @ 9:06 pm BST Jul 24,2009 | Reply

  2. “Both leaf blocks have 11 slots in their ITLs, not the eight that we might expect”

    Shouldn’t it be 4?

    Just so I can get this straight: if a single session inserts 300 rows (or something enough to cause another split) after the other 10 concurrent sessions have commited, then all the “child” blocks will inherit 11 ITL entries, including the service ITL?

    Another question: how do you know if a block is the root, branch or leaf block?

    Comment by Daniel Stolf — July 24, 2009 @ 10:13 pm BST Jul 24,2009 | Reply

    • Daniel,

      You’re right, it should be four; thanks for pointing out the error. Now corrected.

      Yes, every leaf that splits off from either of those two will inherit 11 ITL entries.

      If you do a block dump, the phrase “Leaf block dump” or “Branch block dump” will appear in the header section. However, you cannot, in general, identify a block as “the root block” of an index by looking at the dump – you have to know that it is the first block after the segment header.

      If you happen to know the blevel or height (= blevel + 1) of the index, then you can search for the entry kdxcolev in the dump as this records the level of the block in the index – and if kdxcolev = blevel then you are looking at the root block.

      Comment by Jonathan Lewis — July 24, 2009 @ 10:37 pm BST Jul 24,2009 | Reply

  3. Thank you for explaining the 11th ITL entry it was making me crazy :)

    Comment by coskan — July 24, 2009 @ 11:11 pm BST Jul 24,2009 | Reply

  4. Nice.

    When “playing” the “Index Quiz 2″ I was thinking on this (ehm…wrong) model:

    – every index block start with 4 itc (because I say I want 4 ITC)
    – on block split every block is “initialized” with 4 itc
    – the itc can grow to MAXTRANS

    Quite linear, but quite expensive also because every time a new block is added you have to read the initial INITRANS value.

    The implementation explained by Jonathan is very time effective: it minimize time creation of the block (you have to “copy” the data from the block you are splitting, so no additional look up is required), it also try to optimize concurrency (block are created with a “high” itc so the index is ready for future high transaction burst)

    Comment by lascoltodelvenerdi — July 27, 2009 @ 7:04 am BST Jul 27,2009 | Reply

    • lascoltodelvenerdi,

      Just playing devil’s advocate and talking around the possibilities:

      a) looking up initrans need not be expensive – especially compared to clearing a buffer for the split and writing all that undo and redo; if it gets expensive you could alway ensure that initrans is copied into the root block, and you will probably have pinned the root block already.

      b) the drawback to cloning the ITL is that a single burst of concurrency once in the life time of the index could leave a lot of excess space in the ITL for all new blocks from there onwards. I can’t see any obvious reason why the copy process doesn’t avoid copying ITL entries which have not been used when a split occurs, as this might help to minimise the future wastage.

      Comment by Jonathan Lewis — July 27, 2009 @ 8:15 pm BST Jul 27,2009 | Reply

      • on b.

        You are right (as always! lol!) the reasons can be: HD-space cost is very low (so, some wastage is “not a great problem”) or when split occurs you already got the itc so just copy it (lazy programming technique).
        Possible future enhancements? Maybe…

        As a conclusion:
        When you need to rebuild your index?
        When you got a lot of excess space in the ITL! ;-)
        (just kidding a little bit)

        Comment by lascoltodelvenerdi — July 28, 2009 @ 6:05 am BST Jul 28,2009 | Reply

      • lascoltodelvenerdi,

        I don’t really see this enhancement coming along in the near future – the strategy of copying the ITL has been around since version 6.

        Funny you should mention index rebuilding though …

        Comment by Jonathan Lewis — July 28, 2009 @ 7:47 pm BST Jul 28,2009 | Reply

  5. [...] Index Quiz 2 :  Answering the question with block dumps [...]

    Pingback by Index ITLs « Oracle Scratchpad — September 19, 2009 @ 3:36 pm BST Sep 19,2009 | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Theme: Rubric. Get a free blog at WordPress.com

Follow

Get every new post delivered to your Inbox.

Join 4,090 other followers