Loading

行迁移和行链接

1.行迁移

什么是行迁移

当一个行上发生更新操作,更新后当前数据块无法容纳改行数据,该行数据就会整体迁移到其他数据块中,原来行所在位置仅仅保留一个地址,指向改行所在的位置

行迁移带来的性能问题

通过索引扫描进行回表操作时,原本读到本块地址就会返回数据库。但是发生行迁移之后,读到本行数据列发现仅仅有一个地址指针,需要再多访问一个数据页。
这样使用索引扫描进行检索数据就会比之前要多扫描一个数据块,如果数据量较大情况下,可能就会带来性能上的问题

检查行迁移

@?/rdbms/admin/utlchain.sql --执行该sql会在当前用户下创建一个CHAINED_ROWS表
analyze table table_name list chained rows into chained_rows; --执行该命令会将行迁移的表插入到CHAINED_ROWS表中

预防与解决办法

1.创建表结构的时候调整pctfree大小,将这个值调大
2.碎片整理,通过alter table xxx move或通过中间表方式

--通过创建中间表的方式解决行迁移
create table EMPLOYEES_TMP as select * from EMPLOYEES where rowid in (select head_rowid from chained_rows);
Delete from EMPLOYEES where rowid in (select head_rowid from chained_rows);
Insert into EMPLOYEES select * from EMPLOYEES_TMP;
delete from chained_rows ;
commit;

验证发生行迁移后索引扫描操作会增加一个buffer

创建测试表并创建索引
drop table EMPLOYEES purge;
CREATE TABLE EMPLOYEES AS SELECT * FROM HR.EMPLOYEES ;
create index idx_emp_id on employees(employee_id);

收集统计信息
exec dbms_stats.gather_table_stats('dbmon','employees',cascade=>true,no_invalidate=>false);
创建chained_rows,为检查检查行迁移做准备
@?/rdbms/admin/utlchain.sql
analyze table EMPLOYEES list chained rows into chained_rows;
--检查发现改表没有行迁移发生
SQL> select count(*) from chained_rows;

  COUNT(*)
----------
         0

--查看执行计划,从下面执行计划可以看出,索引扫描耗费了2个buffer,回表时,又增加了一个buffer,一共消耗了3个buffer
select LAST_NAME,FIRST_NAME from employees where employee_id=149

Plan hash value: 2126936620

------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |      1 |        |       |     2 (100)|          |      1 |00:00:00.01 |       3 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES  |      1 |      1 |    19 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       3 |
|*  2 |   INDEX RANGE SCAN          | IDX_EMP_ID |      1 |      1 |       |     1   (0)| 00:00:01 |      1 |00:00:00.01 |       2 |
------------------------------------------------------------------------------------------------------------------------------------
--执行如下操作后,验证employees是否存在行迁移
alter table EMPLOYEES modify FIRST_NAME VARCHAR2(1000);
alter table EMPLOYEES modify LAST_NAME  VARCHAR2(1000);
alter table EMPLOYEES modify EMAIL VARCHAR2(1000);
alter table EMPLOYEES modify PHONE_NUMBER  VARCHAR2(1000);

UPDATE EMPLOYEES
SET FIRST_NAME = LPAD('1', 1000, '*'), LAST_NAME = LPAD('1', 1000, '*'), EMAIL = LPAD('1', 1000, '*'),
PHONE_NUMBER = LPAD('1', 1000, '*');
--验证行迁移,从如下查询,可以得到确是发生了行迁移,有107行
@?/rdbms/admin/utlchain.sql
analyze table EMPLOYEES list chained rows into chained_rows;
--检查发现改表没有行迁移发生
SQL> select count(*) from chained_rows;

  COUNT(*)
----------
      107
--再次执行SQL,查看执行计划,这里索引消耗了2个buffer,回表时消耗了2个buffer,一共四个buffer,验证之前解释行所在位置仅仅保留一个地址,指向改行所在的位置(这里多一个buffer)

select LAST_NAME,FIRST_NAME from employees where employee_id=149

Plan hash value: 2126936620

------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |      1 |        |       |     2 (100)|          |      1 |00:00:00.01 |       4 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES  |      1 |      1 |    19 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN          | IDX_EMP_ID |      1 |      1 |       |     1   (0)| 00:00:01 |      1 |00:00:00.01 |       2 |
------------------------------------------------------------------------------------------------------------------------------------

2.行链接

什么是行链接

当某行数据量太大,一个block无法存放,就会发生行链接(一行数据存放在多个数据块中),这种情况无法避免

检查行链接

analyze table 表名 validate structure cascade into chained_rows;

posted @ 2021-09-08 18:28  李行行  阅读(231)  评论(0编辑  收藏  举报