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 ...
随机推荐
- java类的加载、链接、初始化
JVM和类的关系 当我们调用JAVA命令运行某个java程序时,该命令将会启动一条java虚拟机进程,不管该java程序有多么复杂,该程序启动了多少个线程,它们都处于该java虚拟机进程里.正如前面介 ...
- Oracle 11g RAC 第二节点root.sh执行失败后再次执行root.sh
Oracle 11g RAC 第二节点root.sh执行失败后再次执行root.sh前,要先清除之前的crs配置信息 # /u01/app/11.2.0/grid/crs/install/rootcr ...
- 不等高cell的搭建(一)
一.界面搭建 1.确定开发模式 如果界面是固定的,可以用xib 界面的一些内容不固定,就用纯代码 cell用什么方式去开发(我们采用纯代码和xib结合的方式) 2 ...
- [转]10个顶级的CSS UI开源框架
随着CSS3和HTML5的流行,我们的WEB页面不仅需要更人性化的设计理念,而且需要更酷的页面特效和用户体验.作为开发者,我们需要了解一些宝贵的CSS UI开源框架资源,它们可以帮助我们更快更好地实现 ...
- javascript 一些常用的验证
只能输入数字 onkeyup="this.value=this.value.replace(/[^\d]/g,'')" onafterpaste="th ...
- android adb shell
http://blog.csdn.net/zyp009/article/details/8332925 最快的Android模拟器Genymotion的安装与使用 http://blog.csdn.n ...
- sql server 查询性能最差的sql语句
SELECT TOP 10 TEXT AS 'SQL Statement' ,last_execution_time AS 'Last Execution Time' ,(total_logical_ ...
- nginx指定配制文件
nginx启动: 未指定配制文件: ./nginx 指定配制文件: /usr/local/nginx/sbin/nginx -c /home/deploy/nginx-wz/conf/nginx.co ...
- 夺命雷公狗—angularjs—6—单条数据的遍历
我们在实际的工作中常常会处理到一些数据的遍历,这些数据都是后端传到前端的,有些公司会让前端帮忙处理一点遍历的工作,废话不多说,直接上代: <!doctype html> <html ...
- session讲解(一)——登录网页练习
第一:登陆网页的表单页面login.php <body> <h1>登陆</h1> <form action="loginchuli.php" ...