05.11.2015 Views

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

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

CHAPTER 9 ■ REDO AND UNDO 335<br />

OK, so now we know that we have lots of dirty blocks on disk. We definitely wrote some of<br />

them out, but we just did not have the room to hold them all. Next, we opened a cursor, but<br />

did not yet fetch a single row. Remember, when we open the cursor, the result set is preordained,<br />

so even though <strong>Oracle</strong> did not actually process a row of data, the act of opening that<br />

result set fixed the point in time the results must be “as of.” Now since we will be fetching the<br />

data we just updated <strong>and</strong> committed, <strong>and</strong> we know no one else is modifying the data, we<br />

should be able to retrieve the rows without needing any undo at all. But that is where the<br />

delayed block cleanout rears its head. The transaction that modified these blocks is so new<br />

that <strong>Oracle</strong> will be obliged to verify that it committed before we begin, <strong>and</strong> if we overwrite that<br />

information (also stored in the undo tablespace), the query will fail. So, here is the opening of<br />

the cursor:<br />

ops$tkyte@ORA10G> variable x refcursor<br />

ops$tkyte@ORA10G> exec open :x for select * from big;<br />

PL/SQL procedure successfully completed.<br />

ops$tkyte@ORA10G> !./run.sh<br />

run.sh is a shell script. It simply fired off nine SQL*Plus sessions using a comm<strong>and</strong>:<br />

$ORACLE_HOME/bin/sqlplus / @test2 1 &<br />

where each SQL*Plus session was passed a different number (that was number 1; there was a<br />

2, 3, <strong>and</strong> so on). The script test2.sql they each ran is as follows:<br />

begin<br />

for i in 1 .. 1000<br />

loop<br />

update small set y = i where x= &1;<br />

commit;<br />

end loop;<br />

end;<br />

/<br />

exit<br />

So, we had nine sessions inside of a tight loop initiate many transactions. The run.sh<br />

script waited for the nine SQL*Plus sessions to complete their work, <strong>and</strong> then we returned to<br />

our session, the one with the open cursor. Upon attempting to print it out, we observe the<br />

following:<br />

ops$tkyte@ORA10G> print x<br />

ERROR:<br />

ORA-01555: snapshot too old: rollback segment number 23 with name "_SYSSMU23$"<br />

too small<br />

no rows selected<br />

As I said, the preceding is a rare case. It took a lot of conditions, all of which must exist<br />

simultaneously to occur. We needed blocks that were in need of a cleanout to exist, <strong>and</strong> these<br />

blocks are rare in <strong>Oracle</strong>8i <strong>and</strong> above. A DBMS_STATS call to collect statistics gets rid of them so<br />

the most common causes—large mass updates <strong>and</strong> bulk loads—should not be a concern,<br />

since the tables need to be analyzed after such operations anyway. Most transactions tend to

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

Saved successfully!

Ooh no, something went wrong!