Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
CHAPTER 9 ■ REDO AND UNDO 333 • A long-running query begins. This query will ultimately read some of those blocks from earlier. This query starts at SCN t1, the read consistent SCN it must roll back data to in order to achieve read consistency. The transaction entry for the modification transaction is still in the undo segment transaction table when we began. • During the query, many commits are made in the system. These transactions do not touch the blocks in question (if they did, then we wouldn’t have the impending problem). • The transaction tables in the undo segments roll around and reuse slots due to the high degree of COMMITs. Most important, the transaction entry for the original modification transaction is cycled over and reused. In addition, the system has reused undo segment extents, so as to prevent a consistent read on the undo segment header block itself. • Additionally, the lowest SCN recorded in the undo segment now exceeds t1 (it is higher than the read-consistent SCN of the query), due to the large number of commits. When our query gets to the block that was modified and committed before it began, it is in trouble. Normally, it would go to the undo segment pointed to by the block and find the status of the transaction that modified it (in other words, it would find the COMMIT SCN of that transaction). If the COMMIT SCN is less than t1, our query can use this block. If the COMMIT SCN is greater than t1, our query must roll back that block. The problem is, however, that our query is unable to determine in this particular case if the COMMIT SCN of the block is greater than or less than t1. It is unsure as to whether it can use that block image or not. The ORA-01555 error then results. To see this, we will create many blocks in a table that need to be cleaned out. We will then open a cursor on that table and allow many small transactions to take place against some other table—not the table we just updated and opened the cursor on. Finally, we will attempt to fetch the data for the cursor. Now, we know that the data required by the cursor will be “OK”—we should be able to see all of it since the modifications to the table would have taken place and been committed before we open the cursor. When we get an ORA-01555 error this time, it will be because of the previously described problem. To set up for this example, we’ll use • The 2MB UNDO_SMALL undo tablespace (again). • A 4MB buffer cache, which is enough to hold about 500 blocks. This is so we can get some dirty blocks flushed to disk to observe this phenomenon. Before we start, we’ll create the big table we’ll be querying: ops$tkyte@ORA10G> create table big 2 as 3 select a.*, rpad('*',1000,'*') data 4 from all_objects a; Table created. ops$tkyte@ORA10G> exec dbms_stats.gather_table_stats( user, 'BIG' ); PL/SQL procedure successfully completed.
334 CHAPTER 9 ■ REDO AND UNDO That table will have lots of blocks as we get about six or seven rows per block using that big data field. Next, we’ll create the small table that the many little transactions will modify: ops$tkyte@ORA10G> create table small ( x int, y char(500) ); Table created. ops$tkyte@ORA10G> insert into small select rownum, 'x' from all_users; 38 rows created. ops$tkyte@ORA10G> commit; Commit complete. ops$tkyte@ORA10G> exec dbms_stats.gather_table_stats( user, 'SMALL' ); PL/SQL procedure successfully completed. Now, we’ll dirty up that big table. We have a very small undo tablespace, so we’ll want to update as many blocks of this big table as possible, all while generating the least amount of undo possible. We’ll be using a fancy UPDATE statement to do that. Basically, the following subquery is finding the “first” rowid of a row on every block. That subquery will return a rowid for each and every database block identifying a single row on it. We’ll update that row, setting a VARCHAR2(1) field. This will let us update all of the blocks in the table (some 8,000 plus in the example), flooding the buffer cache with dirty blocks that will have to be written out (we have room for only 500 right now). We’ll make sure we are using that small undo tablespace as well. To accomplish this and not exceed the capacity of our undo tablespace, we’ll craft an UPDATE statement that will update just the “first row” on each block. The ROW_NUMBER() built-in analytic function is instrumental in this operation; it assigns the number 1 to the “first row” by database block in the table, which would be the single row on the block we would update: ops$tkyte@ORA10G> alter system set undo_tablespace = undo_small; System altered. ops$tkyte@ORA10G> update big 2 set temporary = temporary 3 where rowid in 4 ( 5 select r 6 from ( 7 select rowid r, row_number() over (partition by dbms_rowid.rowid_block_number(rowid) order by rowid) rn 8 from big 9 ) 10 where rn = 1 11 ) 12 / 8045 rows updated. ops$tkyte@ORA10G> commit; Commit complete.
- Page 329 and 330: 284 CHAPTER 9 ■ REDO AND UNDO cri
- Page 331 and 332: 286 CHAPTER 9 ■ REDO AND UNDO Fir
- Page 333 and 334: 288 CHAPTER 9 ■ REDO AND UNDO The
- Page 335 and 336: 290 CHAPTER 9 ■ REDO AND UNDO We
- Page 337 and 338: 292 CHAPTER 9 ■ REDO AND UNDO Wha
- Page 339 and 340: 294 CHAPTER 9 ■ REDO AND UNDO row
- Page 341 and 342: 296 CHAPTER 9 ■ REDO AND UNDO If
- Page 343 and 344: 298 CHAPTER 9 ■ REDO AND UNDO ops
- Page 345 and 346: 300 CHAPTER 9 ■ REDO AND UNDO Inv
- Page 347 and 348: 302 CHAPTER 9 ■ REDO AND UNDO The
- Page 349 and 350: 304 CHAPTER 9 ■ REDO AND UNDO 41
- Page 351 and 352: 306 CHAPTER 9 ■ REDO AND UNDO ins
- Page 353 and 354: 308 CHAPTER 9 ■ REDO AND UNDO So,
- Page 355 and 356: 310 CHAPTER 9 ■ REDO AND UNDO ops
- Page 357 and 358: 312 CHAPTER 9 ■ REDO AND UNDO ops
- Page 359 and 360: 314 CHAPTER 9 ■ REDO AND UNDO •
- Page 361 and 362: 316 CHAPTER 9 ■ REDO AND UNDO ...
- Page 363 and 364: 318 CHAPTER 9 ■ REDO AND UNDO •
- Page 365 and 366: 320 CHAPTER 9 ■ REDO AND UNDO bac
- Page 367 and 368: 322 CHAPTER 9 ■ REDO AND UNDO As
- Page 369 and 370: 324 CHAPTER 9 ■ REDO AND UNDO ops
- Page 371 and 372: 326 CHAPTER 9 ■ REDO AND UNDO wil
- Page 373 and 374: 328 CHAPTER 9 ■ REDO AND UNDO Thi
- Page 375 and 376: 330 CHAPTER 9 ■ REDO AND UNDO ops
- Page 377: 332 CHAPTER 9 ■ REDO AND UNDO Whe
- Page 381 and 382: 336 CHAPTER 9 ■ REDO AND UNDO tou
- Page 383 and 384: 338 CHAPTER 10 ■ DATABASE TABLES
- Page 385 and 386: 340 CHAPTER 10 ■ DATABASE TABLES
- Page 387 and 388: 342 CHAPTER 10 ■ DATABASE TABLES
- Page 389 and 390: 344 CHAPTER 10 ■ DATABASE TABLES
- Page 391 and 392: 346 CHAPTER 10 ■ DATABASE TABLES
- Page 393 and 394: 348 CHAPTER 10 ■ DATABASE TABLES
- Page 395 and 396: 350 CHAPTER 10 ■ DATABASE TABLES
- Page 397 and 398: 352 CHAPTER 10 ■ DATABASE TABLES
- Page 399 and 400: 354 CHAPTER 10 ■ DATABASE TABLES
- Page 401 and 402: 356 CHAPTER 10 ■ DATABASE TABLES
- Page 403 and 404: 358 CHAPTER 10 ■ DATABASE TABLES
- Page 405 and 406: 360 CHAPTER 10 ■ DATABASE TABLES
- Page 407 and 408: 362 CHAPTER 10 ■ DATABASE TABLES
- Page 409 and 410: 364 CHAPTER 10 ■ DATABASE TABLES
- Page 411 and 412: 366 CHAPTER 10 ■ DATABASE TABLES
- Page 413 and 414: 368 CHAPTER 10 ■ DATABASE TABLES
- Page 415 and 416: 370 CHAPTER 10 ■ DATABASE TABLES
- Page 417 and 418: 372 CHAPTER 10 ■ DATABASE TABLES
- Page 419 and 420: 374 CHAPTER 10 ■ DATABASE TABLES
- Page 421 and 422: 376 CHAPTER 10 ■ DATABASE TABLES
- Page 423 and 424: 378 CHAPTER 10 ■ DATABASE TABLES
- Page 425 and 426: 380 CHAPTER 10 ■ DATABASE TABLES
- Page 427 and 428: 382 CHAPTER 10 ■ DATABASE TABLES
CHAPTER 9 ■ REDO AND UNDO 333<br />
• A long-running query begins. This query will ultimately read some of those blocks from<br />
earlier. This query starts at SCN t1, the read consistent SCN it must roll back data to in<br />
order to achieve read consistency. The transaction entry for the modification transaction<br />
is still in the undo segment transaction table when we began.<br />
• During the query, many commits are made in the system. These transactions do not<br />
touch the blocks in question (if they did, then we wouldn’t have the impending<br />
problem).<br />
• The transaction tables in the undo segments roll around <strong>and</strong> reuse slots due to the high<br />
degree of COMMITs. Most important, the transaction entry for the original modification<br />
transaction is cycled over <strong>and</strong> reused. In addition, the system has reused undo segment<br />
extents, so as to prevent a consistent read on the undo segment header block itself.<br />
• Additionally, the lowest SCN recorded in the undo segment now exceeds t1 (it is higher<br />
than the read-consistent SCN of the query), due to the large number of commits.<br />
When our query gets to the block that was modified <strong>and</strong> committed before it began, it is<br />
in trouble. Normally, it would go to the undo segment pointed to by the block <strong>and</strong> find the status<br />
of the transaction that modified it (in other words, it would find the COMMIT SCN of that<br />
transaction). If the COMMIT SCN is less than t1, our query can use this block. If the COMMIT SCN<br />
is greater than t1, our query must roll back that block. The problem is, however, that our<br />
query is unable to determine in this particular case if the COMMIT SCN of the block is greater<br />
than or less than t1. It is unsure as to whether it can use that block image or not. The<br />
ORA-01555 error then results.<br />
To see this, we will create many blocks in a table that need to be cleaned out. We will then<br />
open a cursor on that table <strong>and</strong> allow many small transactions to take place against some<br />
other table—not the table we just updated <strong>and</strong> opened the cursor on. Finally, we will attempt<br />
to fetch the data for the cursor. Now, we know that the data required by the cursor will be<br />
“OK”—we should be able to see all of it since the modifications to the table would have taken<br />
place <strong>and</strong> been committed before we open the cursor. When we get an ORA-01555 error this<br />
time, it will be because of the previously described problem. To set up for this example,<br />
we’ll use<br />
• The 2MB UNDO_SMALL undo tablespace (again).<br />
• A 4MB buffer cache, which is enough to hold about 500 blocks. This is so we can get<br />
some dirty blocks flushed to disk to observe this phenomenon.<br />
Before we start, we’ll create the big table we’ll be querying:<br />
ops$tkyte@ORA10G> create table big<br />
2 as<br />
3 select a.*, rpad('*',1000,'*') data<br />
4 from all_objects a;<br />
Table created.<br />
ops$tkyte@ORA10G> exec dbms_stats.gather_table_stats( user, 'BIG' );<br />
PL/SQL procedure successfully completed.