这是关于Oracle碎片的文章
碎片产生的原因
Oracle 对数据段的管理有一个高水位(HWM, High Water Mark)的概念。高水位是数据段中使用过和未使用过的数据块的分界线。高水位以下的数据块是曾使用过的,以上的是从未被使用或初始化过的。
当表或索引在表空间中频繁地进行DML操作时,表中空闲的数据块(高水位以下)无法被有效的利用,例如一些不连续地空间,无法被有效利用时。数据库的数据块就会产生碎片。
碎片的影响
碎片的产生会导致存储空间利用率低下,并且影响数据库的性能。
以全表扫描为例:
当 Oracle 进行全表扫描(FTS, Full table scan)的操作时,它会读高水位下的所有数据块。当高水位下还有很多空闲空间(碎片),读取这些空闲数据块会降低操作的性能。索引碎片同理(解决办法:重建索引+online)。
产生行链接和行迁移
- 行链接 Row Chaining
当插入数据量大的行的,如果一个Block不能存放一条记录,该记录的一部分会存储到同个Extent中的其他Block,这些block形成一个数据块链。 - 行迁移 Row Migration
当Update的时候导致记录长度增加了,存储的Block已经满了,就会发生行迁移。Oracle会迁移整行数据到一个能够存储下整行数据的Block中,迁移的原始指针指向新的存放行数据的Block,ROWID不变。
当数据行发生链接(chain)或迁移(migrate)时,对其访问将会造成 I/O 性能降低,因为Oracle为获取这些数据行的数据,必须访问更多的数据块(data block)。
- 行链接&行迁移检测方案
-- 检测方案1:
-- 执行脚本创建chained_rows表
@?/rdbms/admin/utlchain.sql
-- 执行分析命令
ANALYZE TABLE 表名 LIST CHAINED ROWS INTO chained_rows;
-- 确认存在行迁移/链接的记录
SELECT owner_name, table_name, head_rowid
FROM chained_rows; -- 检测方案2:
-- 分析表
exec dbms_stats.gather_table_stats(ownname=>'HR',tabname=> 'EMPLOYEES');
-- 查看
SELECT table_name, chain_cnt
FROM user_tables
WHERE table_name = 'EMPLOYEES';
TABLE_NAME CHAIN_CNT
-------------- ----------
EMPLOYEES 891 --产生迁移
- 解决行迁移&行链接思路
行迁移:由UPDATE导致记录超出块空间,需迁移数据(可优化PCTFREE解决)。
行链接:记录长度超块大小(如LOB字段),需调整块大小或拆分表结构
解决方案
1、支持在线操作-在线重定义(dbms_redefinition)
-- 1. 检查表是否可重定义
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('SCOTT', 'EMPLOYEES');-- 2. 创建中间表(结构需包含新列或修改后的定义)
CREATE TABLE employees_interim AS SELECT * FROM employees WHERE 1=0;-- 3. 启动重定义
EXEC DBMS_REDEFINITION.START_REDEF_TABLE('SCOTT', 'EMPLOYEES', 'EMPLOYEES_INTERIM');-- 4. 复制依赖对象(可选,不建议使用,结构手动创建更有把控性)
-- 注意:复