Published on

oracle foreign key primary key constraints performance tuning MTS IOT 9i block size backup rman corrupted column drop rename recovery controlfile backup clone architecture database archives export dump dmp duplicate rows extents segments fragmentation hot cold blobs migration tablespace locally managed redo undo new features rollback ora-1555 shrink free space user password link TNS tnsnames.ora listener java shutdown sequence

  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide


  1. 1. Detecting and Curing Row Migration Administration TipsDetecting and Curing Row MigrationRow migration occurs when an existing row, happily contained within an Oracle Block, isupdated to contain extra information, and finds that there is insufficient free space withinthe block to house the newly-grown record. The primary cause for this is that PCTFREE fora segment has been set too low (PCTFREE is there to stop new inserts taking place in ablock before the block is actually full -thus leaving some wasted space at the top of theblock, expressly for the purpose of allowing existing rows to slosh around within the blockas they are updated).Finding no room to expand within its original block, most of the row is moved off into acompletely new block. All that is left behind in the original block is a small row stub (arow header, if you like), which is used to point to where the real row data is now loacted.This seriously degrades performance, since the index on the segment still points to theoriginal block. That means all access to that row via the index is first directed to theoriginal block -where it discovers the row stub pointing to the new block. Thats twoblocks that have to be read before we can access the row data, rather than the originalone. Doubling your I/O for row access is not exactly what one would recommend as aperformance enhancing tip!!Detecting whether rows have already migrated is therefore important. There are anumber of ways to do it, but the easiest is to issue the following command:ALTER TABLE BLAH COMPUTE STATISTICS;That causes a full table scan to take place (so its not something youd do in the middle of abusy day), and each row to be inspected for pointers to other blocks. (It also calculatesother important statistics for the table which the Cost-based Optimizer uses to generateexecution plans whenever a new SQL statement is thrown at the database).The DBA_TABLES view is then populated with the statistics gathered during the scan, andfor our purposes the killer column is one called CHAIN_CNT. If that contains a non-zeronumber, then you have row migration -or, possibly, row chaining -the column doesntdistinguish between them.To distinguish row migration (which can be fixed) from row chaining (which cant), youneed to know your table column definitions. If the definition included things like CLOB or"BLOB or VARCHAR2(3000), then the number probably reflects row chaining (which iswhere a single row is simply too long to fit into a single Oracle Block, and has to be brokenup and distributed amongst several). If the definition is full of "normal" stuff, likeVARCHAR2(30), NUMBER(8,2) and so on, then it is extremely unlikely that the row simplycant be fitted into a block -in which case, the CHAIN_CNT must represent migrated rows.Copyright © Howard Rogers 2001 10/18/2001 Page 1 of 4
  2. 2. Detecting and Curing Row Migration Administration TipsIf you determine that row migration has taken place, what can you do to fix it up? Firstly,of course, you probably want to adjust PCTFREE for the segment:ALTER TABLE BLAH PCTFREE 30;(or some other percentage that is appropriate).That helps prevent future migration, but it doesnt cure any thats already taken place.For that, you have to recall that the migration happened because rows got updated.Migration does not happen when rows are freshly inserted. So what we need is somethingthat will get all the rows of a table freshly inserted -and that will fix the problem.The easiest way to achieve that (in 8i only, alas) is to issue the following command:ALTER TABLE BLAH MOVE TABLESPACE X;The move tablespace command does not have to reference a completely new tablespace -you can type in the name of the same tablespace in which the table is already housed. Butit does cause every record to be read, and freshly inserted into new blocks, and the freshinsertion means that the row migration is cured. Theres only one slight drawback with thisapproach: you need to rebuild all indexes on the table, since they are left pointing at theblocks where the table used to be.In earlier versions of Oracle (7.x and 8.0) the move command is not available to you, sothe only real option you have is to perform an export of the table, truncate it, and thenrun import for it. Import needs to be run with the IGNORE=Y parameter (otherwise, thefact that the table still exists will cause it to abort with an error). The import will thenproceed to insert all the rows back into the table -and, since these are fresh inserts, rowmigration will be cured. The main drawback to this approach is that until the import isfinished, your Users can have no access to the table data (whereas a move tablespace stillallows query access to the original data whilst the move is taking place). On the plus side,import re-creates all indexes automatically, so they dont need to be rebuilt manually.Both approaches are fairly expensive ways of fixing up row migration: for a large table,theyd both involve massive reads and writes. If the migrated rows are only a relativelysmall proportion of the total number of records (say, 10-20%), there is a more subtle wayof fixing the problem.In principle, it involves copying the rowids of the migrated rows out into a holding table,and using them as a hook by which to delete the rows, and then as a source for re-inserting them (and, being fresh inserts, they fix up the migration problem).The steps are as follows:Copyright © Howard Rogers 2001 10/18/2001 Page 2 of 4
  3. 3. Detecting and Curing Row Migration Administration TipsFirst, run the Oracle-supplied script utlchain.sql (its found in theORACLE_HOME/rdbms/admin directory). It creates a special table called "chained_rows"into which the rowid of the rows suffering from migration are copied when you run thecommand:ANALYZE TABLE ORDER_HIST LIST CHAINED ROWS;You can query that table directly, like this:SELECT * FROM CHAINED_ROWS;OWNER_NAME TABLE_NAME ... HEAD_ROWID TIMESTAMP---------- ---------- ... ------------------ ---------SCOTT EMP ... AAAALUAAHAAAAA1AAA 04-OCT-01SCOTT EMP ... AAAALUAAHAAAAA1AAB 04-OCT-01SCOTT EMP ... AAAALUAAHAAAAA1AAC 04-OCT-01However, the more meaningful approach is to create a holding table to hold the entire rowdata for these rows, using the rowid stored in the chained_rows table as the hook by whichto select them. You do that by running a command like this:CREATE TABLE HOLD_EMPAS SELECT *FROM EMPWHERE ROWID IN(SELECT HEAD_ROWIDFROM CHAINED_ROWSWHERE TABLE_NAME = EMP);Now you use the same sort of sub-select technique to delete the rows suffering migrationout of the original table, like this:DELETE FROM EMPWHERE ROWID IN(SELECT HEAD_ROWIDFROM CHAINED_ROWSWHERE TABLE_NAME = EMP);And finally, you insert the same row data back into the original table, drawing on theholding table contents we created earlier:INSERT INTO EMPSELECT *FROM HOLD_EMP;Copyright © Howard Rogers 2001 10/18/2001 Page 3 of 4
  4. 4. Detecting and Curing Row Migration Administration TipsThe freshly inserted rows will now no longer be migrated rows (you could check that bytruncating the chained_rows table, and doing a fresh analyze table emp list chained rowscommand -this time, a select * from chained_rows should yield zero records).To tidy up, drop the holding table:DROP TABLE INT_ORDER_HISTORY;And finally (if you havent already done so) clear out the chained_rows table:DELETE FROM CHAINED_ROWS; (or you could truncate it).This technique is rather more fiddly than the move tablespace or export-truncate-importones, but it has the distinct advantage that the bulk of the table remains unaffected byyour repair efforts. On a big table, thats a huge benefit.Just in case it isnt clear, in all three cases, you need to change PCTFREE first, otherwisethe fix will be purely temporary: unless the underlying cause of row migration is addressed(i.e., a lack of space in the block to accommodate updates), rows will start migratingagain the first time you do some updates to the table.Copyright © Howard Rogers 2001 10/18/2001 Page 4 of 4