一、行移动
ROW MOVEMENT特性最初是在8i时引入的,其目的是提高分区表的灵活性,这一特性默认是关闭,只要使用一下3个功能才需要打开:
1.Flashback Table
这一功能能帮助我们及时回滚一些误操作,防止数据意外丢失。在使用该功能之前,必须先打开ROW MOVEMENT,否则就会抛ORA-08189错误。
select username, rowid from test_move;
delete from test_move where username = ‘MYTBC’;
commit;
alter table test_move enable row movement;
flashback table test_move to timestamp(systimestamp - interval ‘3’ minute);
–闪回到3分钟前得状态,那时username='MYTBC’记录未被删除。
select username, rowid from test_move;
–查询可知,数据被找回来,此时,再比较flashback前后记录的ROWID,大多数记录的物理位置都变化。
这个过程的内部操作, 可以通过对Flashback Table做SQL Trace来进一步观察。通过Trace,我们不难发现,
Flashback Table实际是通过Flashback Query将表中数据进行了一次删除、插入操作,因此ROWID会发生变化。
2.Shrink Segment (减低表的高水位)
Shrink Segment能帮助我们压缩数据段、整理数据碎片、降低高水位,以提高性能、节省空间。它也同样要求开启ROW MOVEMENT。
select username, rowid from test_move;
delete from test_move where username = ‘MYTBC’;
–这个时候 shrink space 会报10636错误
alter table test_move enable row movement;
alter table test_move shrink space;
select username, rowid from test_move;
我们可以看到在Shrink后,ROWID也变化了。从对其过程的Trace来看,Shrink对数据的改变不是通过SQL实现的,而是通过更底层的函数来实现的。
3.更新Partition Key
在更新记录中的Partition Key时,可能会导致该记录超出当前所在分区的范围,需要将其转移到其他对应分区上,因此要求开启ROW MOVEMENT。
drop table test_move;
create table test_move
partition by list (owner)
(partition p1 values (‘SYS’),
partition p2 values (‘DEMO’),
partition p3 values (‘SYSTEM’),
partition def values (default))
as select * from dba_tables;
–这个时候update会报14402错误
alter table test_move enable row movement;
update test_move set owner=‘SYS’ where owner=‘DEMO’ and table_name=‘T_TEST’;
这一操作产生影响的特殊之处在于这是个DML操作,是和online transaction密切相关。对于这样一个UPDATE,实际上分为3步:先从原有分区将数据删除;将原数据转移到新分区上;更新数据。
其影响就在于以下几个方面:
一个UPDATE被分解为DELET、INSERT、UPDATE三个操作,增加了性能负担。其中,DELETE的查询条件与原UPDATE的查询条件相同,新的UPDATE的查询条件是基于INSERT生成的新的ROWID;
相应的Redo Log、Undo Log会增加;
如果Update语句还涉及到了Local Index的字段的话,新、旧2个分区上的Local Index都要被更新。
还有一点,Row Movement会和域索引(Domain Index)产生冲突:如果表上定义了域索引,开启Row Movement就会失败;反之亦然。
有必要说明一下,行移动(row movement)并不是行迁移(Row Migration),最大的区别是行迁移的rowid是不变的,行迁移是update 行记录时,数据块没有足够的空闲容纳数据行,Oracle将此行移到其他数据块,同时保留此行的rowid不变,并在原数据块建一指针指向新的行位置。这种情况下,读取一行数据就会访问2个数据块,增加IO,导致性能下降。
二、行链接(Row chaining) 与行迁移(Row Migration)
当一行的数据过长而不能插入一个单个数据块中时,可能发生两种事情:行链接(row chaining)或行迁移(row migration)。
行链接
当第一次插入行时,由于行太长而不能容纳在一个数据块中时,就会发生行链接。在这种情况下,oracle会使用与该块链接的一块或多块数据块来容纳该行的数据。行连接经常在插入比较大的行时才会发生,如包含long, long row, lob等类型的数据。在这些情况下行链接是不可避免的。
行迁移
当修改不是行链接的行时,当修改后的行长度大于修改前的行长度,并且该数据块中的空闲空间已经比较小而不能完全容纳该行的数据时,就会发生行迁移。在这种情况下,Oracle会将整行的数据迁移到一个新的数据块上,而将该行原先的空间只放一个指针,指向该行的新的位置,并且该行原先空间的剩余空间不再被数据库使用,这些剩余的空间我们将其称之为空洞,这就是产生表碎片的主要原因,表碎片基本上也是不可避免的,但是我们可以将其降到一个我们可以接受的程度。注意,即使发生了行迁移,发生了行迁移的行的rowid 还是不会变化,这也是行迁移会引起数据库I/O性能降低的原因。其实行迁移是行链接的一种特殊形式,但是它的起因与行为跟行链接有很大不同,所以一般把它从行链接中独立出来,单独进行处理。
行迁移(row migration):由于在table 的pctfree 设置过小,在update 这个table并使其行长增大的时候,就有可能因为块的剩余空间不够存储该行,oracle会把该行数据迁移到另外一个有足够空闲空间的block中,此即发生了行迁移;发生行迁移时,行rowid并不变,原先存储该行的地方增加了一个新的指针,该指针指向迁移后的block id,所以我们在访问发生了行迁移的行时,会要读取迁移前和迁移后的2个block,一个表如果有大量的行发生了row migration,那么就有必要查看该table的storage 设置了,看看pctpree是否可以调整的更大一点。
行链接和行迁移引起数据库性能下降的原因:
引起性能下降的原因主要是由于引起多余的I/O造成的。当通过索引访问已有行迁移现象的行时,数据库必须扫描一个以上的数据块才能检索到改行的数据。这主要有一下两种表现形式:
- row migration 或row chaining 导致 INSERT 或 UPDATE语句的性能比较差,因为它们需要执行额外的处理
- 利用索引查询已经链接或迁移的行的select语句性能比较差,因为它们要执行额外的I/O
产生原因:当Update时,Update更新的数据大于数据块得PCTFREE值,就需要申请第二个块,从而形成行迁移。
预防方法:1. 将数据块的PCTFREE调大;2. 针对表空间扩大数据块大小
行链接,行迁移检查:analyze table 表名 validate structure cascade into chained_rows;
行连接,行迁移处理:可以在EM管理器中针对表进行reorganize。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29699285/viewspace-2724668/,如需转载,请注明出处,否则将追究法律责任。