Contenu connexe Similaire à Migration (20) Plus de oracle documents (20) Migration1. Detecting and Curing Row Migration Administration Tips
Detecting and Curing Row Migration
Row migration occurs when an existing row, happily contained within an Oracle Block, is
updated to contain extra information, and finds that there is insufficient free space within
the block to house the newly-grown record. The primary cause for this is that PCTFREE for
a segment has been set too low (PCTFREE is there to stop new inserts taking place in a
block before the block is actually full -thus leaving some wasted space at the top of the
block, expressly for the purpose of allowing existing rows to slosh around within the block
as they are updated).
Finding no room to expand within its original block, most of the row is moved off into a
completely new block. All that is left behind in the original block is a small row stub (a
row 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 the
original block. That means all access to that row via the index is first directed to the
original block -where it discovers the row stub pointing to the new block. That's two
blocks that have to be read before we can access the row data, rather than the original
one. Doubling your I/O for row access is not exactly what one would recommend as a
performance enhancing tip!!
Detecting whether rows have already migrated is therefore important. There are a
number 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 it's not something you'd do in the middle of a
busy day), and each row to be inspected for pointers to other blocks. (It also calculates
other important statistics for the table which the Cost-based Optimizer uses to generate
execution 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, and
for our purposes the killer column is one called CHAIN_CNT. If that contains a non-zero
number, then you have row migration -or, possibly, row chaining -the column doesn't
distinguish between them.
To distinguish row migration (which can be fixed) from row chaining (which can't), you
need 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 is
where a single row is simply too long to fit into a single Oracle Block, and has to be broken
up and distributed amongst several). If the definition is full of "normal" stuff, like
'VARCHAR2(30)', 'NUMBER(8,2) and so on, then it is extremely unlikely that the row simply
can't 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. Detecting and Curing Row Migration Administration Tips
If 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 doesn't cure any that's 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 something
that 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. But
it does cause every record to be read, and freshly inserted into new blocks, and the fresh
insertion means that the row migration is cured. There's only one slight drawback with this
approach: you need to rebuild all indexes on the table, since they are left pointing at the
blocks where the table used to be.
In earlier versions of Oracle (7.x and 8.0) the move command is not available to you, so
the only real option you have is to perform an export of the table, truncate it, and then
run import for it. Import needs to be run with the 'IGNORE=Y' parameter (otherwise, the
fact that the table still exists will cause it to abort with an error). The import will then
proceed to insert all the rows back into the table -and, since these are fresh inserts, row
migration will be cured. The main drawback to this approach is that until the import is
finished, your Users can have no access to the table data (whereas a 'move tablespace' still
allows query access to the original data whilst the move is taking place). On the plus side,
import re-creates all indexes automatically, so they don't need to be rebuilt manually.
Both approaches are fairly expensive ways of fixing up row migration: for a large table,
they'd both involve massive reads and writes. If the migrated rows are only a relatively
small proportion of the total number of records (say, 10-20%), there is a more subtle way
of fixing the problem.
In principle, it involves copying the rowid's 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. Detecting and Curing Row Migration Administration Tips
First, run the Oracle-supplied script utlchain.sql (it's found in the
ORACLE_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 the
command:
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-01
SCOTT EMP ... AAAALUAAHAAAAA1AAB 04-OCT-01
SCOTT EMP ... AAAALUAAHAAAAA1AAC 04-OCT-01
However, the more meaningful approach is to create a holding table to hold the entire row
data for these rows, using the rowid stored in the chained_rows table as the hook by which
to select them. You do that by running a command like this:
CREATE TABLE HOLD_EMP
AS SELECT *
FROM EMP
WHERE ROWID IN
(SELECT HEAD_ROWID
FROM CHAINED_ROWS
WHERE TABLE_NAME = 'EMP');
Now you use the same sort of sub-select technique to delete the rows suffering migration
out of the original table, like this:
DELETE FROM EMP
WHERE ROWID IN
(SELECT HEAD_ROWID
FROM CHAINED_ROWS
WHERE TABLE_NAME = 'EMP');
And finally, you insert the same row data back into the original table, drawing on the
holding table contents we created earlier:
INSERT INTO EMP
SELECT *
FROM HOLD_EMP;
Copyright © Howard Rogers 2001 10/18/2001 Page 3 of 4
4. Detecting and Curing Row Migration Administration Tips
The freshly inserted rows will now no longer be migrated rows (you could check that by
truncating the chained_rows table, and doing a fresh 'analyze table emp list chained rows'
command -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 haven't 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-import'
ones, but it has the distinct advantage that the bulk of the table remains unaffected by
your repair efforts. On a big table, that's a huge benefit.
Just in case it isn't clear, in all three cases, you need to change PCTFREE first, otherwise
the 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 migrating
again the first time you do some updates to the table.
Copyright © Howard Rogers 2001 10/18/2001 Page 4 of 4