行链接 行迁移的消除_长烟慢慢的博客-程序员宅基地

技术标签: oracle基础知识  

模拟行链接:

如何模仿行链接?

首先要了解三个语句:
第1句:运行$ORACLE_HOME/rdbms/admin/utlchain.sql 脚本,SQL> @D:\oracle\product\10.1.0\Db_1\RDBMS\ADMIN\utlchain.sql创建 chained_rows表,用于存放发生行迁移         的行的rowid。
第2句:运行analyze table table_name list chained rows into chained_rows; 把产生行迁移的rowid 移动到这个表中。
第3句:运行select * from chained_rows where table_name= 'table_name'; 查看产生的行迁移的rowid。

行链接好模仿,如下:

SQL> create table test (x int primary key ,a char(2000),b char(2000),c char(2000),d char(2000),e char(2000)) tablespace test2;
test2的块大小是8K,5个char(2000)的字段,这样每行记录约为10k。肯定超过一个块大小。

SQL> insert into test (x) values (1);
SQL> commit;


SQL> select * from CHAINED_ROWS ;
未选定行

此时还没产生行链接,

SQL> update test set a='test',b='test',c='test',e='test' where x=1;

已更新 1 行。

SQL> commit;

提交完成。

SQL> ANALYZE TABLE test LIST CHAINED ROWS;

表已分析。

SQL> select * from CHAINED_ROWS;

    TABLE_NAME     HEAD_ROWID         
----------------------- --------- ------------------------------                           

  TEST               AAAMFaAAHAAACVCAAA
可见产生的是行链接,因为一个块的大小只有8k,而此时这条记录的大小已经约为10k,意味着将跨数据块存储。

那么请问,如何模仿行迁移呢?
下面是一种模仿行迁移的办法:

block的大小为:8k
[email protected]>create table test (id int,name varchar2(4000),job varchar2(2200),sal varchar(2000) ) 
pctfree 0 pctused 99;
表已创建。

[email protected]>insert into test values(1,'dd','xx','sss');
已创建 1 行。

[email protected]>insert into test values(2,'dx','xx','sss');
已创建 1 行。

[email protected]>insert into test values(3,'dx','xx','sss');
已创建 1 行。

[email protected]>insert into test values(4,'dx','xx','sss');
已创建 1 行。

[email protected]>commit;
提交完成。

[email protected]>update test set name=RPAD('Z',4000,'Z') where id=4;
已更新 1 行。

[email protected]>commit;
提交完成。

[email protected]>select dbms_rowid.rowid_block_number(rowid) as block_number from test;

BLOCK_NUMBER
------------
         106
         106
         106
         106

可见所有的记录都是在106号数据块里面。

[email protected]>ANALYZE TABLE test LIST CHAINED ROWS;

表已分析。

[email protected]>select * from CHAINED_ROWS;

此时并没有产生行链接或者行迁移。
----执行完上一条update的时候(也就是update test set name=RPAD('Z',4000,'Z') where id=4;),此块剩下的大小不足4k;所以执行下面的update将肯定导致行迁移。
[email protected]>update test set job=RPAD('J',2200,'J'),sal=RPAD('S',2000,'S') where id=3;

已更新 1 行。

[email protected]>commit;
提交完成。


[email protected]>ANALYZE TABLE test LIST CHAINED ROWS;
表已分析。

[email protected]>select * from CHAINED_ROWS;

OWNER_NAME      TABLE_NAME      CLUSTER_NAME     PARTITION_NAME     SUBPARTITION_NAME        HEAD_ROWID          ANALYZE_TI
------------  -------------- ---------------- ------------------    ------------------- ----------------          ----------
TEST             TEST                                                    N/A              AAAOqKAAKAAAABqAAC      25-1月 -10


[email protected]>select id from test where rowid in (select head_rowid from chained_rows);

    ID
-------
    3
可见是ID为3的记录产生了行迁移。而此时ID为3的记录所在的块号是不会变化的,尽管是行迁移:

[email protected]>select dbms_rowid.rowid_block_number(rowid) as block_number from test;

BLOCK_NUMBER
------------
         106
         106
         106
         106

-------下面将通过简单的delete insert 的方式来解决这个行迁移的问题:

[email protected]>create table temp as select * from test  where rowid in (select head_rowid from chained_rows);

表已创建。

[email protected]>delete from test  where rowid in (select head_rowid from chained_rows);

已删除 1 行。

[email protected]>commit;

提交完成。

[email protected]>select id from test;

        ID
----------
         1
         2
         4

[email protected]>select id from temp;

        ID
----------
         3

[email protected]>select * from chained_rows;

OWNER_NAME        TABLE_NAME       CLUSTER_NAME       PARTITION_NAME     SUBPARTITION_NAME           HEAD_ROWID           ANALYZE_TI
------------- ------------------ ---------------- ------------------   -------------------        ------------------        -------
TEST                 TEST                                                    N/A                AAAOqKAAKAAAABqAAC        25-1月 -10


而此时chained_rows表里还有之前的行迁移的统计信息,好,我们删了,从新来过:
[email protected]>ANALYZE TABLE test LIST CHAINED ROWS;
表已分析。

[email protected]>select * from CHAINED_ROWS;
未选定行

对表从新分析后,可见行迁移已经被干掉了。我们再来看看block number:
[email protected]>select dbms_rowid.rowid_block_number(rowid) as block_number from test;
BLOCK_NUMBER
------------
         106
         106
         106
         107

[email protected]>select dbms_rowid.rowid_block_number(rowid) as block_number from test
    where rowid=(select rowid from test where id=3);


BLOCK_NUMBER
------------
         107

可见test表里,id为3的记录已经被从106号数据块里放到了107号数据块里面,而不是像之前的那样:在106号数据块id=3的那条记录里存储了一个指向其他数据块的地址。此时id=3的记录已经被单独放到了107号数据块里。
总结:
行迁移可以通过简单的delete,insert该条数据的方式解决。而行链接的话delete和insert的方式是不能见效的。行链接只有考虑使用更大的数据块,来解决。

总结行清除行迁移的各种方法:

1、传统的清除行迁移的方法

具体步骤如下:

(1)执行$ORACLE_HOME/rdbms/admin目录下的 utlchain.sql脚本创建chained_rows表。

(2)将存在行迁移的表(此处用table_name 代替) 中的产生行迁移的行的rowid 放入到chained_rows表中。

analyze table table_name list chained rows into chained_rows;

(3)将表中行迁移的rowid 放入临时表中保存

create table table_name_temp as select * from table_name where rowid in (select head_rowid from chained_rows where table_name= 'table_name');

(4) 删除表中原来存在的行迁移的记录行

delete table_name where rowid in (select head_rowid from chained_rows where table_name= 'table_name');

(5)从临时表中取出且重新把那些被删除了的数据插入到原来的表中,并删除临时表

insert into table_name select * from table_name_temp;

drop table table_name_temp;

这种传统的清除行迁移(RM)的方法,优点是执行起来的比较简单,容易实现。但是这种算法的缺陷是没有考虑到表关联的情况。但是在真正的数据库应用中,很多表都是和别的表关联在一起的,如果有外键的限制,这样步骤3中的delete是不能删除那条发生行迁移的行的。这种方法在插入和删除行的时候没有disable掉索引,这样导致时间删除和插入时维持索引树的均衡上了,如果记录数多的话,耗时太严重。


2、改进的清除行迁移的方法

(1)执行$ORACLE_HOME/rdbms/admin目录下的 utlchain.sql脚本创建chained_rows表。

(2)禁用所有其他表上关联到此表的所有限制。

(3)将表中行迁移的rowid 放入临时表中保存

create table table_name_temp as select * from table_name where rowid in (select head_rowid from chained_rows where table_name= 'table_name');

(4) 删除表中原来存在的行迁移的记录行

delete table_name where rowid in (select head_rowid from chained_rows where table_name= 'table_name');

(5)从临时表中取出且重新把那些被删除了的数据插入到原来的表中,并删除临时表

insert into table_name select * from table_name_temp;

drop table table_name_temp;

(6)启用所有其他表上关联到此表的所有限制。

下面是一个具体的示例:

select index_name,index_type,table_name from user_indexes where table_name= 'TERMINAL'; —— 查出表对应的索引

select constraint_name,constraint_type,table_name from user_constraints where r_constraint_name = 'PK_TERMINAL_ID'; ——查出外键对应的表

alter table 外键表 disable constraint sys_c003200

创建临时表——插入有行连接的数据行——删除原表中有行连接的行。——将临时表中的数据插入原表——删除临时表——启用限制

3、使用toad工具清除行迁移的方法

4、使用emp/imp工具清除行迁移的方法


检查行迁移的方法:
1)        运行$ORACLE_HOME/rdbms/admin/utlchain.sql
2)        analyze table table_name list chained rows into CHAINED_ROWS
3)        select * from CHAINED_ROWS where table_name='table_name';
清除的方法:
方法1:create table table_name_tmp as select * from table_name where rowed in (select head_rowid from chained_rows);
       Delete from table_name where rowed in (select head_rowid from chained_rows);
       Insert into table_name select * from table_name_tmp;
方法2:create table table_name_tmp select * from table_name ;
truncate table table_name
insert into table_name select * from table_name_tmp
方法3:用exp工具导出表,然后删除这个表,最后用imp工具导入这表
方法4:alter table table_name move tablespace tablespace_name,然后再重新表的索引
上面的4种方法可以用以消除已经存在的行迁移现象,但是行迁移的产生很多情况下时由于PCT_FREE参数设置的太小所导致,所以需要调整PCT_FREE参数的值。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/changyanmanman/article/details/7532072

智能推荐

听说最近你读过不少书 - java学习必读书单_chuixuan3775的博客-程序员宅基地

那些时光 噢,很久没有看过书了——此刻的你心里是否会发出这样的感慨? 我们总是怪工作太忙,总是怪应酬多、活动多;今天想着去哪玩,明天想着约妹纸……究竟什么时候会想着好好地静下心来翻一翻上面早已布满灰尘的书呢? 我理解,那部电视剧确实很精彩;我理解,那游戏确实很好玩。但是当某一天,你会...

TypeScript笔记(5)—— 基本数据类型_jcLee95的博客-程序员宅基地

TypeScript(5):基本数据类型1. let关键字JavaScript中使用关键字var来声明变量有很多的缺陷,首先一个就是var作用域的问题。比如:for (var i = 0; i < 5; i++) { console.log('for循环内,迭代变量i=' + i) }console.log('for循环外:,迭代变量i=' + i)可想而知,由于使用var声明的变量作用域比较宽松,在for语句等一些语句中,由var声明的变量可能受到外部的干扰而导

influxdb写入mysql_InfluxDB学习之InfluxDB的HTTP API写入操作_勉强解惑强行胡诌的博客-程序员宅基地

HTTP API也有两种操作:写入和查询,本文就先给大家介绍一下 InfluxDB的HTTP API的写入操作方式。在InfluxDB学习的上一篇文章:InfluxDB学习之InfluxDB的基本操作中,我们提到 InfluxDB操作有三种方式,其中一种是HTTP API的方式。HTTP API也有两种操作:写入和查询,本文就先给大家介绍一下 InfluxDB的HTTP API的写入操作方式。更...

E010Web学习笔记-Tomcat_訾博ZiBo的博客-程序员宅基地

一、web相关概念回顾1、软件架构C/S架构:客户端/服务器端;B/S架构:浏览器/服务端;浏览器内含静态资源解析引擎;浏览器请求数据,服务器响应来自浏览器的请求;2、资源分类静态资源:每个用户访问后得到的结果是一样的;直接返回给浏览器,浏览器内含静态资源解析引擎;如:html,css,js;动态资源:每个用户访问相同资源后得到的结果可...

winform窗体中嵌入网页(DHTML代码和winfrom应用程序交互)_wangchaoqi1985的博客-程序员宅基地_winform中嵌入html

本文转载自:https://www.cnblogs.com/charles2008/archive/2009/08/08/1541968.html 作者:Charles2008 转载请注明该声明。 在开发RFID项目中,看到同事在winform中加入网页。界面用Css和JavaScript做出来的效果很不错,比直接用winform做出来的效果好得多。更何况winform在页面表现上...

elastic5.6安装及配置_李思苇的博客-程序员宅基地

单节点elasticsearch.yml注意配置:bootstrap.memory_lock: true # disable swapping bootstrap.system_call_filter: falsejvm.options将xms与xmx设定为同样大小的值,以防止jvm的resize。/etc/security/limits.conf...

随便推点

python算因数之和是_python找出因数与质因数的方法_weixin_39786341的博客-程序员宅基地

最近有一个学弟问我一些求解质因数的问题,帮他解决问题的同时自己也试着写了几个差不多效果的脚本,有很多不同的思路,以下是相关脚本。n = int(input("input number: ")) # 输入数字fac = [] # 定义一个列表存放因子for i in range(2, n): # 这里的逻辑和你一样if n % i == 0:fac.append(i) # 如果是因子就放进去cont...

linux命令vgdisplay提示权限不足,vgdisplay_程秧秧的博客-程序员宅基地

磁盘信息[[email protected] ~]# fdisk -lDisk /dev/hda: 41.1 GB, 41174138880 bytes255 heads, 63 sectors/track, 5005 cylindersUnits = cylinders of 16065 * 512 = 8225280 bytesDevice Boot Start End Bl...

jQuery.validate 中文API_ahtzday206576的博客-程序员宅基地

(HappyCZX)名称返回类型描述validate(options)返回:Validator验证所选的FORMvalid()返回:Boolean检查是否验证通过rules()返回:Options返回元素的验证规则rules("add...

html5视频云桌面重定向,web版云桌面OpenStack功能修改说明_Jacob Jia的博客-程序员宅基地

版本说明:openstack Pike操作系统:centos 7.3一、功能需求(1)云桌面用户权限配置在Openstack中建立云桌面用户,并配置菜单功能权限。 (2)云桌面用户实例管理功能配置好的云桌面用户实现对被分配的实例进行操作。 (3)实例用户管理功能项目下增加用户管理功能,实现在项目实例下增加删除用户。 二、原功能说明不具备该项功能。三、功能实现1、horizon修改增加程序文件:...

TeeChart Pro VCL/FMX教程(二):图表显示属性(Panel和page篇)_weixin_34220834的博客-程序员宅基地

下载TeeChart Pro VCL/FMX最新版本本教程将为您介绍在TeeChart Pro VCL/FMX的图表显示属性(Panel和page篇)。Panel属性TeeChart Panel页面允许您设置可以大大增强图表外观的参数。支持真彩色的显示器最能看到面板渐变效果,但255色屏幕上的某些颜色组合是非常可接受的。到目前为止,您熟悉TeeChart属性,因此我们不会在此处运行所有属性...

CMD应用 qtp/winshell/cmd的交互_蜕变之痛的博客-程序员宅基地

==================================================================='采用windows.shell的 sendkeys 方式:set objshell=createobject("wscript.shell")objshell.run("cmd")objshell.SendKeys("{ENTER}")objs