05.11.2015 Views

Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

CHAPTER 9 ■ REDO AND UNDO 297<br />

• Some of the blocks our transaction modified will be visited <strong>and</strong> “cleaned out” in a<br />

fast mode if they are still in the buffer cache. Block cleanout refers to the lock-related<br />

information we store in the database block header. Basically, we are cleaning out our<br />

transaction information on the block, so the next person who visits the block won’t<br />

have to. We are doing this in a way that need not generate redo log information, saving<br />

considerable work later (this is discussed more fully in the upcoming “Block Cleanout”<br />

section).<br />

As you can see, there is very little to do to process a COMMIT. The lengthiest operation is,<br />

<strong>and</strong> always will be, the activity performed by LGWR, as this is physical disk I/O. The amount of<br />

time spent by LGWR here will be greatly reduced by the fact that it has already been flushing the<br />

contents of the redo log buffer on a recurring basis. LGWR will not buffer all of the work you do<br />

for as long as you do it; rather, it will incrementally flush the contents of the redo log buffer in<br />

the background as you are going along. This is to avoid having a COMMIT wait for a very long<br />

time in order to flush all of your redo at once.<br />

So, even if we have a long-running transaction, much of the buffered redo log it generates<br />

would have been flushed to disk, prior to committing. On the flip side of this is the fact that<br />

when we COMMIT, we must wait until all buffered redo that has not been written yet is safely on<br />

disk. That is, our call to LGWR is a synchronous one. While LGWR may use asynchronous I/O to<br />

write in parallel to our log files, our transaction will wait for LGWR to complete all writes <strong>and</strong><br />

receive confirmation that the data exists on disk before returning.<br />

Now, earlier I mentioned that we were using a Java program <strong>and</strong> not PL/SQL for a reason—<br />

<strong>and</strong> that reason is a PL/SQL commit-time optimization. I said that our call to LGWR is a<br />

synchronous one, <strong>and</strong> that we wait for it to complete its write. That is true in <strong>Oracle</strong> 10g<br />

Release 1 <strong>and</strong> before for every programmatic language except PL/SQL. The PL/SQL engine,<br />

realizing that the client does not know whether or not a COMMIT has happened in the PL/SQL<br />

routine until the PL/SQL routine is completed, does an asynchronous commit. It does not<br />

wait for LGWR to complete; rather, it returns from the COMMIT call immediately. However, when<br />

the PL/SQL routine is completed, when we return from the database to the client, the PL/SQL<br />

routine will wait for LGWR to complete any of the outst<strong>and</strong>ing COMMITs. So, if you commit 100<br />

times in PL/SQL <strong>and</strong> then return to the client, you will likely find you waited for LGWR once—<br />

not 100 times—due to this optimization. Does this imply that committing frequently in<br />

PL/SQL is a good or OK idea? No, not at all—just that it is not as bad an idea as it is in other<br />

languages. The guiding rule is to commit when your logical unit of work is complete—not<br />

before.<br />

■Note This commit-time optimization in PL/SQL may be suspended when you are performing distributed<br />

transactions or Data Guard in maximum availability mode. Since there are two participants, PL/SQL must<br />

wait for the commit to actually be complete before continuing on.<br />

To demonstrate that a COMMIT is a “flat response time” operation, we’ll generate varying<br />

amounts of redo <strong>and</strong> time the INSERTs <strong>and</strong> COMMITs. To do this, we’ll again use AUTOTRACE in<br />

SQL*Plus. We’ll start with a big table of test data we’ll insert into another table <strong>and</strong> an empty<br />

table:

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!