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.

268<br />

CHAPTER 8 ■ TRANSACTIONS<br />

it is in fact much faster, but still much slower than it could be. Not only that, but you should<br />

notice that the code is getting more <strong>and</strong> more complex. From the sheer simplicity of a single<br />

UPDATE statement, to procedural code, to even more complex procedural code—we are going<br />

in the wrong direction!<br />

Now, just to supply a counterpoint to this discussion, recall in Chapter 7 when we discussed<br />

the concept of write consistency <strong>and</strong> how an UPDATE statement, for example, could be<br />

made to restart. In the event that the preceding UPDATE statement was to be performed against<br />

a subset of the rows (it had a WHERE clause), <strong>and</strong> other users were modifying the columns this<br />

UPDATE was using in the WHERE clause, then there would be a case either for using a series of<br />

smaller transactions rather than one large transaction or for locking the table prior to performing<br />

the mass update. The goal here would be to reduce the opportunity for restarts to<br />

occur. If we were to UPDATE the vast majority of the rows in the table, that would lead us toward<br />

using the LOCK TABLE comm<strong>and</strong>. In my experience, however, these sorts of large mass updates<br />

or mass deletes (the only statement types really that would be subject to the restart) are done<br />

in isolation. That large, one-time bulk update or the purge of old data generally is not done<br />

during a period of high activity. Indeed, the purge of data should not be affected by this at all,<br />

since you would typically use some date field to locate the information to purge, <strong>and</strong> other<br />

applications would not modify this data.<br />

Snapshot Too Old Error<br />

Let’s now look at the second reason developers are tempted to commit updates in a procedural<br />

loop, which arises from their (misguided) attempts to use a “limited resource” (undo<br />

segments) sparingly. This is a configuration issue; you need to ensure that you have enough<br />

undo space to size your transactions correctly. Committing in a loop, apart from generally<br />

being slower, is also the most common cause of the dreaded ORA-01555 error. Let’s look at this<br />

in more detail.<br />

As you will appreciate after reading Chapters 1 <strong>and</strong> 7, <strong>Oracle</strong>’s multi-versioning model<br />

uses undo segment data to reconstruct blocks as they appeared at the beginning of your statement<br />

or transaction (depending on the isolation mode). If the necessary undo information no<br />

longer exists, you will receive an ORA-01555: snapshot too old error message, <strong>and</strong> your query<br />

will not complete. So, if you are modifying the table that you are reading (as in the previous<br />

example), you are generating undo information required for your query. Your UPDATE generates<br />

undo information that your query will probably be making use of to get the read-consistent<br />

view of the data it needs to update. If you commit, you are allowing the system to reuse the<br />

undo segment space you just filled up. If it does reuse the undo, wiping out old undo data that<br />

your query subsequently needs, you are in big trouble. Your SELECT will fail <strong>and</strong> your UPDATE<br />

will stop partway through. You have a part-finished logical transaction <strong>and</strong> probably no good<br />

way to restart it (more about this in a moment).<br />

Let’s see this concept in action with a small demonstration. In a small test database, I set<br />

up a table:<br />

ops$tkyte@ORA10G> create table t as select * from all_objects;<br />

Table created.<br />

ops$tkyte@ORA10G> create index t_idx on t(object_name);<br />

Index created.

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

Saved successfully!

Ooh no, something went wrong!