Oracle 行迁移和行链接
一、行迁移
1.1、行迁移概念
当一个行上的更新操作(原来的数据存在且没有减少)导致当前的数据不能在容纳在当前块,我们需要进行行迁移。一个行迁移意味着整行数据将会移动,仅仅保留的是一个转移地址。因此整行数据都被移动,原始的数据块上仅仅保留的是指向新块的一个地址信息。
成因:当行被update时,如果update更新的行大于数据块的pctfree值,就需要申请第2个块,从而形成迁移。
后果:导致应用需要访问更多的数据块,性能下降。
预防:1.将数据块的pctfree调大;
2.针对表空间扩大数据块的大小。
检查:analyze table 表名 validate structure cascade into chained_rows;
2.1、实例:
实验说明:
(以EMPLOYEES表为例,如果涉及到该表有主键,并且有别的表的外键REFERENCE关联到本表,必须要执行步骤2和步骤7,否则不必执行);
1. 执行$ORACLE_HOME/rdbms/admin目录下的utlchain.sql脚本创建chained_rows表。
2. 禁用所有其它表上关联到此表上的所有限制(假想EMPLOYEES表有主键PK_EMPLOYEES_ID,假想test表有外键f_employees_id关联reference到employees表)。
select index_name,index_type,table_name from user_indexes where table_name='EMPLOYEES';
select CONSTRAINT_NAME,CONSTRAINT_TYPE,TABLE_NAME from USER_CONSTRAINTS where R_CONSTRAINT_NAME='PK_EMPLOYEES_ID';
alter table test disable constraint f_employees_id;
3. 将存在有行迁移的表(用table_name代替)中的产生行迁移的行的rowid放入到chained_rows表中。
4. 将表中的行迁移的row id放入临时表中保存。
5. 删除原来表中存在的行迁移的记录行。
6. 从临时表中取出并重新插入那些被删除了的数据到原来的表中,并删除临时表。
7. 启用所有其它表上关联到此表上的所有限制。
alter table test enable constraint f_employees_id;
此外还可以采用move和exp/imp的方式(特别注意move会导致索引失效,需要重建索引)。
----创建实验表----
SQL> DROP TABLE EMPLOYEES PURGE;
DROP TABLE EMPLOYEES PURGE
*
第 1 行出现错误:
ORA-00942: 表或视图不存在 SQL> CREATE TABLE EMPLOYEES AS SELECT * FROM HR.EMPLOYEES ; 表已创建。 SQL> desc EMPLOYEES;
名称 是否为空? 类型
----------------------------------------- -------- ----------------------------
EMPLOYEE_ID NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4) SQL> create index idx_emp_id on employees(employee_id); 索引已创建。 ---扩大字段----
SQL> alter table EMPLOYEES modify FIRST_NAME VARCHAR2(1000); 表已更改。 SQL> alter table EMPLOYEES modify LAST_NAME VARCHAR2(1000); 表已更改。 SQL> alter table EMPLOYEES modify EMAIL VARCHAR2(1000); 表已更改。 SQL> alter table EMPLOYEES modify PHONE_NUMBER VARCHAR2(1000); 表已更改。 SQL> desc employees;
名称 是否为空? 类型
----------------------------------------- -------- ----------------------------
EMPLOYEE_ID NUMBER(6)
FIRST_NAME VARCHAR2(1000)
LAST_NAME NOT NULL VARCHAR2(1000)
EMAIL NOT NULL VARCHAR2(1000)
PHONE_NUMBER VARCHAR2(1000)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4) ----更新表----
SQL> UPDATE EMPLOYEES
2 SET FIRST_NAME = LPAD('', 1000, '*'), LAST_NAME = LPAD('', 1000, '*'), EMAIL = LPAD('', 1000, '*'),
3 PHONE_NUMBER = LPAD('', 1000, '*'); 已更新107行。 SQL> commit; 提交完成。 ----行迁移优化前,先看看该语句逻辑读情况(执行计划及代价都一样,没必要展现了,就展现statistics即可)----
SQL> set autotrace traceonly stat
SQL> set linesize 1000
SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0; 已选择107行。 统计信息
----------------------------------------------------------
152 recursive calls
0 db block gets
310 consistent gets
0 physical reads
0 redo size
437664 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
9 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
107 rows processed SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0; 已选择107行。 统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
219 consistent gets
0 physical reads
0 redo size
437664 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
9 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
107 rows processed SQL> set autotrace off ----- 发现存在行迁移的方法
--首先建chaind_rows相关表,这是必需的步骤
SQL> drop table chained_rows purge;
drop table chained_rows purge
*
第 1 行出现错误:
ORA-00942: 表或视图不存在 SQL> @?/rdbms/admin/utlchain.sql 表已创建。
----以下命令针对EMPLOYEES表和EMPLOYEES_BK做分析,将产生行迁移的记录插入到chained_rows表中 SQL> analyze table EMPLOYEES list chained rows into chained_rows; 表已分析。 SQL> select count(*) from chained_rows where table_name='EMPLOYEES'; COUNT(*)
----------
105
---以下方法可以去除行迁移
SQL> drop table EMPLOYEES_TMP;
drop table EMPLOYEES_TMP
*
第 1 行出现错误:
ORA-00942: 表或视图不存在 SQL> create table EMPLOYEES_TMP as select * from EMPLOYEES where rowid in (select head_rowid from chained_rows); 表已创建。 SQL> Delete from EMPLOYEES where rowid in (select head_rowid from chained_rows); 已删除105行。 SQL> Insert into EMPLOYEES select * from EMPLOYEES_TMP; 已创建105行。 SQL> delete from chained_rows ; 已删除105行。 SQL> commit; 提交完成。 SQL> analyze table EMPLOYEES list chained rows into chained_rows; 表已分析。 SQL> select count(*) from chained_rows where table_name='EMPLOYEES'; COUNT(*)
----------
0 --这时的取值一定为0,用这种方法做行迁移消除,肯定是没问题的! ---行迁移优化后,先看看该语句逻辑读情况(执行计划及代价都一样,没必要展现了,就展现statistics即可)
SET AUTOTRACE traceonly statistics
SQL> set linesize 1000
SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0; 已选择107行。 统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
116 consistent gets
0 physical reads
0 redo size
437034 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
9 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
107 rows processed
二、行链接
2.1、行链接概念
当一行数据太大而不能在一个单数据块容纳时,行链接由此产生。举例来说,当你使用了4kb的Oracle数据块大小,而你需要插入一行数据是8k,Oracle则需要使用3个数据块分成片来存储。因此,引起行链接的情形通常是,表上行记录的大小超出了数据库Oracle块的大小。
产生原因:当一行数据大于一个数据块,ORACLE会同时分配两个数据块,并在第一个块上登记第二个块的地址,从而形成行链接。
预防方法:针对表空间扩大数据块大小。
检查:analyze table 表名 validate structure cascade into chained_rows;
----建表----
SQL> DROP TABLE EMPLOYEES PURGE; 表已删除。 SQL> CREATE TABLE EMPLOYEES AS SELECT * FROM HR.EMPLOYEES ; 表已创建。 SQL> set linesize 80;
SQL> desc EMPLOYEES;
名称 是否为空? 类型
----------------------------------------- -------- ----------------------------
EMPLOYEE_ID NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4) SQL> create index idx_emp_id on employees(employee_id); 索引已创建。
----扩大字段----
SQL> alter table EMPLOYEES modify FIRST_NAME VARCHAR2(2000); 表已更改。 SQL> alter table EMPLOYEES modify LAST_NAME VARCHAR2(2000); 表已更改。 SQL> alter table EMPLOYEES modify EMAIL VARCHAR2(2000); 表已更改。 SQL> alter table EMPLOYEES modify PHONE_NUMBER VARCHAR2(2000); 表已更改。
----更新表----
UPDATE EMPLOYEES
SET FIRST_NAME = LPAD('', 2000, '*'), LAST_NAME = LPAD('', 2000, '*'), EMAIL = LPAD('', 2000, '*'),
PHONE_NUMBER = LPAD('', 2000, '*');
COMMIT; 已更新107行。 SQL>
提交完成。 -----行链接移优化前,先看看该语句逻辑读情况
SET AUTOTRACE traceonly
SQL> set linesize 1000
SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0;
统计信息
----------------------------------------------------------
153 recursive calls
1 db block gets
415 consistent gets
0 physical reads
176 redo size
868529 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
9 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
107 rows processed
SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0; 已选择107行。 统计信息
----------------------------------------------------------
7 recursive calls
0 db block gets
397 consistent gets
0 physical reads
0 redo size
868529 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
9 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
107 rows processed SQL> set autotrace off
--------- 发现存在行链接的方法
--首先建chaind_rows相关表,这是必需的步骤
SQL> drop table chained_rows purge; 表已删除。 SQL> @?/rdbms/admin/utlchain.sql 表已创建。 ----以下命令针对EMPLOYEES表和EMPLOYEES_BK做分析,将产生行迁移的记录插入到chained_rows表中 SQL> analyze table EMPLOYEES list chained rows into chained_rows; 表已分析。 SQL> select count(*) from chained_rows where table_name='EMPLOYEES'; COUNT(*)
----------
107 ---用消除行迁移的方法根本无法消除行链接!!! SQL> drop table EMPLOYEES_TMP; 表已删除。 SQL> create table EMPLOYEES_TMP as select * from EMPLOYEES where rowid in (select head_rowid from chained_rows); 表已创建。 SQL> Delete from EMPLOYEES where rowid in (select head_rowid from chained_rows); 已删除107行。 SQL> Insert into EMPLOYEES select * from EMPLOYEES_TMP; 已创建107行。 SQL> delete from chained_rows ; 已删除107行。 SQL> commit; 提交完成。
--发现用消除行迁移的方法根本无法消除行链接!
SQL> analyze table EMPLOYEES list chained rows into chained_rows; 表已分析。 SQL> select count(*) from chained_rows where table_name='EMPLOYEES'; COUNT(*)
----------
107 SQL> SET AUTOTRACE traceonly stat
SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0; 已选择107行。 统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
223 consistent gets
0 physical reads
0 redo size
867923 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
9 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
107 rows processed ---启动大小为32K的块新建表空间(WINDOWS下只能使用2K,4K,8K和16K)
--行链接只有通过加大BLOCK块的方式才可以避免,如下:
create tablespace TBS_JACK_16k
blocksize 16k
datafile '/u01/app/oracle/oradata/orcl/TBS_JACK_32K_01.dbf' size 100m
autoextend on
extent management local
6 segment space management auto;
create tablespace TBS_JACK_16k
*
第 1 行出现错误:
ORA-29339: 表空间块大小 16384 与配置的块大小不匹配
------------------ORA-29339报错解决办法! ----解决问题后再次创建表空间----
SQL> / 表空间已创建。 SQL> DROP TABLE EMPLOYEES_BK PURGE;
DROP TABLE EMPLOYEES_BK PURGE
*
第 1 行出现错误:
ORA-00942: 表或视图不存在
SQL> CREATE TABLE EMPLOYEES_BK TABLESPACE TBS_JACK_16K AS SELECT * FROM EMPLOYEES; 表已创建。 SQL> delete from chained_rows ; 已删除107行。
SQL> analyze table EMPLOYEES_BK list chained rows into chained_rows; 表已分析。 SQL> select count(*) from chained_rows where table_name='EMPLOYEES_BK'; COUNT(*)
----------
0
Oracle 行迁移和行链接的更多相关文章
- 模拟Oracle行迁移和行链接
行链接消除方法创建大的block块------------------ 参考tom kyte的例子----------------------------------------------创建4k ...
- oracle 11g sql优化之行迁移处理(加大BLOCK块)
行链接 产生原因:当一行数据大于一个数据块,ORACLE会同时分配两个数据块,并在第一个块上登记第二个块的地址,从而形成行链接. 预防方法:针对表空间扩大数据块大小.检查:analyze table ...
- [20180327]行迁移与ITL浪费.txt
[20180327]行迁移与ITL浪费.txt --//生产系统遇到的一个问题,增加一个字段到表结构,修改数据字典,导致出现行迁移,而更加严重的是没有修改pctfree值,--//以后的业务操作,依旧 ...
- 【oracle11g,17】存储结构: 段的类型,数据块(行连接、行迁移,块头),段的管理方式,高水位线
一.段的类型: 1.什么是段:段是存储单元. 1.段的类型有: 表 分区表 簇表 索引 索引组织表(IOT表) 分区索引 暂时段 undo段 lob段(blob ,clob) 内嵌表(record类型 ...
- oracle 分组取第一行数据 ,查询sql语句
oracle 分组取第一行数据 SELECT * FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY x ORDER BY y DESC) rn, t.* FR ...
- Oracle JDK迁移指南
Oracle JDK迁移指南 https://docs.oracle.com/en/java/javase/11/migrate/index.html#JSMIG-GUID-C25E2B1D-6C24 ...
- Oracle 数据库迁移到MySQL (kettle,navicate,sql developer等工具
Oracle 数据库迁移到MySQL (kettle,navicate,sql developer等工具 1 kettle --第一次使用kettle玩迁移,有什么不足之处和建议,请大家指正和建议. ...
- Oracle 服务器迁移的一些经验
前言 通过此文章来分享一下 Oracle 服务器迁移过程中的一些经验,希望对大家有些许帮助. 本文旨在帮助更多的同学,会提及一些基本命令或技巧,但不赘述,后续有机会再进一步分享各个细节. 背景 之前因 ...
- jquery Datatables 行数据删除、行上升、行下降功能演示
Datatables 是一款jquery表格插件.它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能. 官方网站:http://www.datatables.net Datatables ...
随机推荐
- linux普通用户权限设置为超级用户权限方法、sudo不用登陆密码
以用户zato为例 普通用户权限设置为超级用户权限 进入有超级用户权限的账号 添加文件可写(w)权限 sudo chmod u+x /etc/sudoers 编辑/etc/sudoers文件 添加语句 ...
- linux系统服务名称
服务列表(按字母顺序排列) 服务名 必需(是/否) 用途描述 acon 否 语言支持 acpi 否 电源管理 acpid 否 监听精灵进程 adsl 否 内部ADSL开关控制 alsa 否 高级Lin ...
- Http authentication(BASIC, DIGEST)
Http authentication....BASIC: In the context of an HTTP transaction, basic access authentication is ...
- ssh隧道技术
大家都知道SSH是一种安全的传输协议,用在连接服务器上比较多.不过其实除了这个功能,它的隧道转发功能更是吸引人.下面是个人根据自己的需求以及在网上查找的资料配合自己的实际操作所得到的一些心得. SSH ...
- ios判断点击的坐标点
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSSet *allTouches = [event allTouc ...
- 数据存储之plist、偏好设置
// 偏好设置--------------------------------- // 存储基本类型数据 NSUserDefaults *defaults = [NSUserDefaults stan ...
- mongodb的连接和开启安全验证
首先是启动mongodb a.打开cmd,cd进入mongodb的安装目录下的bin目录下面,执行 mongod --dbpath D:\MongoDBdata(数据存放的目录) 或者将mongodb ...
- Winform 窗口拖动
把窗口边框去掉后,窗口拖动问题: private Point mouseOffset; //记录鼠标指针的坐标 private bool isMouseDown = false; //记录鼠标按键是否 ...
- java中的BigDecimal和String的相互转换
/*由数字字符串构造BigDecimal的方法 02.*设置BigDecimal的小数位数的方法 03.*/ 04.import java.math.BigDecimal; 05.//数字字符串 06 ...
- manacher 最长回文子串
确定当前已知能匹配到的最长处,看是否要更新最长 #include <bits/stdc++.h> using namespace std; const int N = 210005; in ...