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 ...
随机推荐
- RabbitMQ学习总结 第一篇:理论篇
目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...
- [BS] 小知识点总结-04
1. ios新知识学习思路: 在开发过程中如果遇到某种新需求以前从未做过,例如改变textField的Placeholder颜色,有如下思路和途径: 1.1 在Storyboard/Xib辅助编辑器A ...
- makefile中引用其他makefile方法
在Makefile中引用其他Makefile文件的方法是,使用inclue filename.mk
- Vue.2.0.5-Class 与 Style 绑定
Class 与 Style 绑定 数据绑定一个常见需求是操作元素的 class 列表和它的内联样式.因为它们都是属性 ,我们可以用v-bind 处理它们:只需要计算出表达式最终的字符串.不过,字符串拼 ...
- iOS 自定义UITableViewCell
#import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> @pr ...
- Autorelease pool
根据苹果官方文档中对 Using Autorelease Pool Blocks 的描述,我们知道在下面三种情况下是需要我们手动添加 autoreleasepool 的: 如果你编写的程序不是基于 U ...
- Fix the “No Private Key” Error Message
This article will show you how to correct the “No Private Key” error message in Windows Internet Inf ...
- Java基础之读文件——使用通道读取混合数据1(ReadPrimesMixedData)
控制台程序,本例读取Java基础之写文件部分(PrimesToFile2)写入的Primes.txt. 方法一:可以在第一个读操作中读取字符串的长度,然后再将字符串和二进制素数值读入到文本中.这种方式 ...
- Java-NIO-Selector
扩展阅读: Java NIO类库Selector机制解析(上) Java NIO类库Selector机制解析(下) Java NIO的选择器 三个重要的类: 1,Selector 选择器,完成主要的选 ...
- Inventory Pro 装备拾取的实现
以后都按照插件使用,提出问题,回答问题的方式来进行总结和学习 效果图 1.运行相关的例子,场景中出现4个矩形,这4个矩形是用来模拟物品掉落的包裹,移动Player靠近物品 2.使用鼠标点击物品正方体, ...