一、行迁移

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会导致索引失效,需要重建索引)。

  1. ----创建实验表----
  2. SQL> DROP TABLE EMPLOYEES PURGE;
  3. DROP TABLE EMPLOYEES PURGE
  4. *
  5. 1 行出现错误:
  6. ORA-00942: 表或视图不存在
  7.  
  8. SQL> CREATE TABLE EMPLOYEES AS SELECT * FROM HR.EMPLOYEES ;
  9.  
  10. 表已创建。
  11.  
  12. SQL> desc EMPLOYEES;
  13. 名称 是否为空? 类型
  14. ----------------------------------------- -------- ----------------------------
  15. EMPLOYEE_ID NUMBER(6)
  16. FIRST_NAME VARCHAR2(20)
  17. LAST_NAME NOT NULL VARCHAR2(25)
  18. EMAIL NOT NULL VARCHAR2(25)
  19. PHONE_NUMBER VARCHAR2(20)
  20. HIRE_DATE NOT NULL DATE
  21. JOB_ID NOT NULL VARCHAR2(10)
  22. SALARY NUMBER(8,2)
  23. COMMISSION_PCT NUMBER(2,2)
  24. MANAGER_ID NUMBER(6)
  25. DEPARTMENT_ID NUMBER(4)
  26.  
  27. SQL> create index idx_emp_id on employees(employee_id);
  28.  
  29. 索引已创建。
  30.  
  31. ---扩大字段----
  32. SQL> alter table EMPLOYEES modify FIRST_NAME VARCHAR2(1000);
  33.  
  34. 表已更改。
  35.  
  36. SQL> alter table EMPLOYEES modify LAST_NAME VARCHAR2(1000);
  37.  
  38. 表已更改。
  39.  
  40. SQL> alter table EMPLOYEES modify EMAIL VARCHAR2(1000);
  41.  
  42. 表已更改。
  43.  
  44. SQL> alter table EMPLOYEES modify PHONE_NUMBER VARCHAR2(1000);
  45.  
  46. 表已更改。
  47.  
  48. SQL> desc employees;
  49. 名称 是否为空? 类型
  50. ----------------------------------------- -------- ----------------------------
  51. EMPLOYEE_ID NUMBER(6)
  52. FIRST_NAME VARCHAR2(1000)
  53. LAST_NAME NOT NULL VARCHAR2(1000)
  54. EMAIL NOT NULL VARCHAR2(1000)
  55. PHONE_NUMBER VARCHAR2(1000)
  56. HIRE_DATE NOT NULL DATE
  57. JOB_ID NOT NULL VARCHAR2(10)
  58. SALARY NUMBER(8,2)
  59. COMMISSION_PCT NUMBER(2,2)
  60. MANAGER_ID NUMBER(6)
  61. DEPARTMENT_ID NUMBER(4)
  62.  
  63. ----更新表----
  64. SQL> UPDATE EMPLOYEES
  65. 2 SET FIRST_NAME = LPAD('', 1000, '*'), LAST_NAME = LPAD('', 1000, '*'), EMAIL = LPAD('', 1000, '*'),
  66. 3 PHONE_NUMBER = LPAD('', 1000, '*');
  67.  
  68. 已更新107行。
  69.  
  70. SQL> commit;
  71.  
  72. 提交完成。
  73.  
  74. ----行迁移优化前,先看看该语句逻辑读情况(执行计划及代价都一样,没必要展现了,就展现statistics即可)----
  75. SQL> set autotrace traceonly stat
  76. SQL> set linesize 1000
  77. SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0;
  78.  
  79. 已选择107行。
  80.  
  81. 统计信息
  82. ----------------------------------------------------------
  83. 152 recursive calls
  84. 0 db block gets
  85. 310 consistent gets
  86. 0 physical reads
  87. 0 redo size
  88. 437664 bytes sent via SQL*Net to client
  89. 492 bytes received via SQL*Net from client
  90. 9 SQL*Net roundtrips to/from client
  91. 0 sorts (memory)
  92. 0 sorts (disk)
  93. 107 rows processed
  94.  
  95. SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0;
  96.  
  97. 已选择107行。
  98.  
  99. 统计信息
  100. ----------------------------------------------------------
  101. 0 recursive calls
  102. 0 db block gets
  103. 219 consistent gets
  104. 0 physical reads
  105. 0 redo size
  106. 437664 bytes sent via SQL*Net to client
  107. 492 bytes received via SQL*Net from client
  108. 9 SQL*Net roundtrips to/from client
  109. 0 sorts (memory)
  110. 0 sorts (disk)
  111. 107 rows processed
  112.  
  113. SQL> set autotrace off
  114.  
  115. ----- 发现存在行迁移的方法
  116. --首先建chaind_rows相关表,这是必需的步骤
  117. SQL> drop table chained_rows purge;
  118. drop table chained_rows purge
  119. *
  120. 1 行出现错误:
  121. ORA-00942: 表或视图不存在
  122.  
  123. SQL> @?/rdbms/admin/utlchain.sql
  124.  
  125. 表已创建。
  126. ----以下命令针对EMPLOYEES表和EMPLOYEES_BK做分析,将产生行迁移的记录插入到chained_rows表中
  127.  
  128. SQL> analyze table EMPLOYEES list chained rows into chained_rows;
  129.  
  130. 表已分析。
  131.  
  132. SQL> select count(*) from chained_rows where table_name='EMPLOYEES';
  133.  
  134. COUNT(*)
  135. ----------
  136. 105
  137. ---以下方法可以去除行迁移
  138. SQL> drop table EMPLOYEES_TMP;
  139. drop table EMPLOYEES_TMP
  140. *
  141. 1 行出现错误:
  142. ORA-00942: 表或视图不存在
  143.  
  144. SQL> create table EMPLOYEES_TMP as select * from EMPLOYEES where rowid in (select head_rowid from chained_rows);
  145.  
  146. 表已创建。
  147.  
  148. SQL> Delete from EMPLOYEES where rowid in (select head_rowid from chained_rows);
  149.  
  150. 已删除105行。
  151.  
  152. SQL> Insert into EMPLOYEES select * from EMPLOYEES_TMP;
  153.  
  154. 已创建105行。
  155.  
  156. SQL> delete from chained_rows ;
  157.  
  158. 已删除105行。
  159.  
  160. SQL> commit;
  161.  
  162. 提交完成。
  163.  
  164. SQL> analyze table EMPLOYEES list chained rows into chained_rows;
  165.  
  166. 表已分析。
  167.  
  168. SQL> select count(*) from chained_rows where table_name='EMPLOYEES';
  169.  
  170. COUNT(*)
  171. ----------
  172. 0
  173.  
  174. --这时的取值一定为0,用这种方法做行迁移消除,肯定是没问题的!
  175.  
  176. ---行迁移优化后,先看看该语句逻辑读情况(执行计划及代价都一样,没必要展现了,就展现statistics即可)
  177. SET AUTOTRACE traceonly statistics
  178. SQL> set linesize 1000
  179. SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0;
  180.  
  181. 已选择107行。
  182.  
  183. 统计信息
  184. ----------------------------------------------------------
  185. 0 recursive calls
  186. 0 db block gets
  187. 116 consistent gets
  188. 0 physical reads
  189. 0 redo size
  190. 437034 bytes sent via SQL*Net to client
  191. 492 bytes received via SQL*Net from client
  192. 9 SQL*Net roundtrips to/from client
  193. 0 sorts (memory)
  194. 0 sorts (disk)
  195. 107 rows processed

二、行链接

2.1、行链接概念

当一行数据太大而不能在一个单数据块容纳时,行链接由此产生。举例来说,当你使用了4kb的Oracle数据块大小,而你需要插入一行数据是8k,Oracle则需要使用3个数据块分成片来存储。因此,引起行链接的情形通常是,表上行记录的大小超出了数据库Oracle块的大小。

产生原因:当一行数据大于一个数据块,ORACLE会同时分配两个数据块,并在第一个块上登记第二个块的地址,从而形成行链接。

预防方法:针对表空间扩大数据块大小。

检查:analyze table 表名 validate structure cascade into chained_rows;

  1. ----建表----
  2. SQL> DROP TABLE EMPLOYEES PURGE;
  3.  
  4. 表已删除。
  5.  
  6. SQL> CREATE TABLE EMPLOYEES AS SELECT * FROM HR.EMPLOYEES ;
  7.  
  8. 表已创建。
  9.  
  10. SQL> set linesize 80;
  11. SQL> desc EMPLOYEES;
  12. 名称 是否为空? 类型
  13. ----------------------------------------- -------- ----------------------------
  14. EMPLOYEE_ID NUMBER(6)
  15. FIRST_NAME VARCHAR2(20)
  16. LAST_NAME NOT NULL VARCHAR2(25)
  17. EMAIL NOT NULL VARCHAR2(25)
  18. PHONE_NUMBER VARCHAR2(20)
  19. HIRE_DATE NOT NULL DATE
  20. JOB_ID NOT NULL VARCHAR2(10)
  21. SALARY NUMBER(8,2)
  22. COMMISSION_PCT NUMBER(2,2)
  23. MANAGER_ID NUMBER(6)
  24. DEPARTMENT_ID NUMBER(4)
  25.  
  26. SQL> create index idx_emp_id on employees(employee_id);
  27.  
  28. 索引已创建。
  29. ----扩大字段----
  30. SQL> alter table EMPLOYEES modify FIRST_NAME VARCHAR2(2000);
  31.  
  32. 表已更改。
  33.  
  34. SQL> alter table EMPLOYEES modify LAST_NAME VARCHAR2(2000);
  35.  
  36. 表已更改。
  37.  
  38. SQL> alter table EMPLOYEES modify EMAIL VARCHAR2(2000);
  39.  
  40. 表已更改。
  41.  
  42. SQL> alter table EMPLOYEES modify PHONE_NUMBER VARCHAR2(2000);
  43.  
  44. 表已更改。
  45. ----更新表----
  46. UPDATE EMPLOYEES
  47. SET FIRST_NAME = LPAD('', 2000, '*'), LAST_NAME = LPAD('', 2000, '*'), EMAIL = LPAD('', 2000, '*'),
  48. PHONE_NUMBER = LPAD('', 2000, '*');
  49. COMMIT;
  50.  
  51. 已更新107行。
  52.  
  53. SQL>
  54. 提交完成。
  55.  
  56. -----行链接移优化前,先看看该语句逻辑读情况
  57. SET AUTOTRACE traceonly
  58. SQL> set linesize 1000
  59. SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0;
  60. 统计信息
  61. ----------------------------------------------------------
  62. 153 recursive calls
  63. 1 db block gets
  64. 415 consistent gets
  65. 0 physical reads
  66. 176 redo size
  67. 868529 bytes sent via SQL*Net to client
  68. 492 bytes received via SQL*Net from client
  69. 9 SQL*Net roundtrips to/from client
  70. 0 sorts (memory)
  71. 0 sorts (disk)
  72. 107 rows processed
  73. SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0;
  74.  
  75. 已选择107行。
  76.  
  77. 统计信息
  78. ----------------------------------------------------------
  79. 7 recursive calls
  80. 0 db block gets
  81. 397 consistent gets
  82. 0 physical reads
  83. 0 redo size
  84. 868529 bytes sent via SQL*Net to client
  85. 492 bytes received via SQL*Net from client
  86. 9 SQL*Net roundtrips to/from client
  87. 0 sorts (memory)
  88. 0 sorts (disk)
  89. 107 rows processed
  90.  
  91. SQL> set autotrace off
  92. --------- 发现存在行链接的方法
  93. --首先建chaind_rows相关表,这是必需的步骤
  94. SQL> drop table chained_rows purge;
  95.  
  96. 表已删除。
  97.  
  98. SQL> @?/rdbms/admin/utlchain.sql
  99.  
  100. 表已创建。
  101.  
  102. ----以下命令针对EMPLOYEES表和EMPLOYEES_BK做分析,将产生行迁移的记录插入到chained_rows表中
  103.  
  104. SQL> analyze table EMPLOYEES list chained rows into chained_rows;
  105.  
  106. 表已分析。
  107.  
  108. SQL> select count(*) from chained_rows where table_name='EMPLOYEES';
  109.  
  110. COUNT(*)
  111. ----------
  112. 107
  113.  
  114. ---用消除行迁移的方法根本无法消除行链接!!!
  115.  
  116. SQL> drop table EMPLOYEES_TMP;
  117.  
  118. 表已删除。
  119.  
  120. SQL> create table EMPLOYEES_TMP as select * from EMPLOYEES where rowid in (select head_rowid from chained_rows);
  121.  
  122. 表已创建。
  123.  
  124. SQL> Delete from EMPLOYEES where rowid in (select head_rowid from chained_rows);
  125.  
  126. 已删除107行。
  127.  
  128. SQL> Insert into EMPLOYEES select * from EMPLOYEES_TMP;
  129.  
  130. 已创建107行。
  131.  
  132. SQL> delete from chained_rows ;
  133.  
  134. 已删除107行。
  135.  
  136. SQL> commit;
  137.  
  138. 提交完成。
  139. --发现用消除行迁移的方法根本无法消除行链接!
  140. SQL> analyze table EMPLOYEES list chained rows into chained_rows;
  141.  
  142. 表已分析。
  143.  
  144. SQL> select count(*) from chained_rows where table_name='EMPLOYEES';
  145.  
  146. COUNT(*)
  147. ----------
  148. 107
  149.  
  150. SQL> SET AUTOTRACE traceonly stat
  151. SQL> select /*+index(EMPLOYEES,idx_emp_id)*/ * from EMPLOYEES where employee_id>0;
  152.  
  153. 已选择107行。
  154.  
  155. 统计信息
  156. ----------------------------------------------------------
  157. 0 recursive calls
  158. 0 db block gets
  159. 223 consistent gets
  160. 0 physical reads
  161. 0 redo size
  162. 867923 bytes sent via SQL*Net to client
  163. 492 bytes received via SQL*Net from client
  164. 9 SQL*Net roundtrips to/from client
  165. 0 sorts (memory)
  166. 0 sorts (disk)
  167. 107 rows processed
  168.  
  169. ---启动大小为32K的块新建表空间(WINDOWS下只能使用2K,4K8K16K)
  170. --行链接只有通过加大BLOCK块的方式才可以避免,如下:
  171. create tablespace TBS_JACK_16k
  172. blocksize 16k
  173. datafile '/u01/app/oracle/oradata/orcl/TBS_JACK_32K_01.dbf' size 100m
  174. autoextend on
  175. extent management local
  176. 6 segment space management auto;
  177. create tablespace TBS_JACK_16k
  178. *
  179. 1 行出现错误:
  180. ORA-29339: 表空间块大小 16384 与配置的块大小不匹配
  181. ------------------ORA-29339报错解决办法!
  182.  
  183. ----解决问题后再次创建表空间----
  184. SQL> /
  185.  
  186. 表空间已创建。
  187.  
  188. SQL> DROP TABLE EMPLOYEES_BK PURGE;
  189. DROP TABLE EMPLOYEES_BK PURGE
  190. *
  191. 1 行出现错误:
  192. ORA-00942: 表或视图不存在
  193. SQL> CREATE TABLE EMPLOYEES_BK TABLESPACE TBS_JACK_16K AS SELECT * FROM EMPLOYEES;
  194.  
  195. 表已创建。
  196.  
  197. SQL> delete from chained_rows ;
  198.  
  199. 已删除107行。
  200. SQL> analyze table EMPLOYEES_BK list chained rows into chained_rows;
  201.  
  202. 表已分析。
  203.  
  204. SQL> select count(*) from chained_rows where table_name='EMPLOYEES_BK';
  205.  
  206. COUNT(*)
  207. ----------
  208. 0

Oracle 行迁移和行链接的更多相关文章

  1. 模拟Oracle行迁移和行链接

    行链接消除方法创建大的block块------------------ 参考tom kyte的例子----------------------------------------------创建4k ...

  2. oracle 11g sql优化之行迁移处理(加大BLOCK块)

    行链接 产生原因:当一行数据大于一个数据块,ORACLE会同时分配两个数据块,并在第一个块上登记第二个块的地址,从而形成行链接. 预防方法:针对表空间扩大数据块大小.检查:analyze table ...

  3. [20180327]行迁移与ITL浪费.txt

    [20180327]行迁移与ITL浪费.txt --//生产系统遇到的一个问题,增加一个字段到表结构,修改数据字典,导致出现行迁移,而更加严重的是没有修改pctfree值,--//以后的业务操作,依旧 ...

  4. 【oracle11g,17】存储结构: 段的类型,数据块(行连接、行迁移,块头),段的管理方式,高水位线

    一.段的类型: 1.什么是段:段是存储单元. 1.段的类型有: 表 分区表 簇表 索引 索引组织表(IOT表) 分区索引 暂时段 undo段 lob段(blob ,clob) 内嵌表(record类型 ...

  5. oracle 分组取第一行数据 ,查询sql语句

    oracle  分组取第一行数据 SELECT * FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY x ORDER BY y DESC) rn, t.* FR ...

  6. Oracle JDK迁移指南

    Oracle JDK迁移指南 https://docs.oracle.com/en/java/javase/11/migrate/index.html#JSMIG-GUID-C25E2B1D-6C24 ...

  7. Oracle 数据库迁移到MySQL (kettle,navicate,sql developer等工具

    Oracle 数据库迁移到MySQL (kettle,navicate,sql developer等工具 1 kettle --第一次使用kettle玩迁移,有什么不足之处和建议,请大家指正和建议. ...

  8. Oracle 服务器迁移的一些经验

    前言 通过此文章来分享一下 Oracle 服务器迁移过程中的一些经验,希望对大家有些许帮助. 本文旨在帮助更多的同学,会提及一些基本命令或技巧,但不赘述,后续有机会再进一步分享各个细节. 背景 之前因 ...

  9. jquery Datatables 行数据删除、行上升、行下降功能演示

    Datatables 是一款jquery表格插件.它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能. 官方网站:http://www.datatables.net Datatables ...

随机推荐

  1. Redis一些基本的操作

    代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...

  2. 教你安装CentOS 6.5如何选择安装包

    近来发现越来越多的运维小伙伴们都有最小化安装CentOS 6.5系统的洁癖,因此,找老男孩来咨询,这个“洁癖”好习惯啊,必须支持,,因此发布本文和大家分享下. (1)系统安装类型选择及自定义额外包组 ...

  3. hadoop map reduce 实例wordcount的使用

    hadoop jar hadoop-mapreduce-examples-2.7.3.jar wordcount /wordcount.txt /wc/output3

  4. 如何调试DLL组件

    因为DLL组件不像EXE是程序的入口,所以DLL需要其他进程的调用才能调试. 1.首先在DLL项目中你想调试的位置打好断点. 2.如果已经有一个进程,比如foo.exe已经启动,那么就用:调试> ...

  5. category分类

    /* 使用继承关系来扩充一个类,有一个弊病,高耦合性 category(分类,类别) 能够帮我们扩充一个类的功能 */ - (void)superJump { //    [self eat]; [s ...

  6. JAVA NIO系列(三) Buffer 解读

    缓冲区分类 NIO中的buffer用于和通道交互,数据是从通道读入缓冲区,从缓冲区中写入通道的.Buffer就像一个数组,可以保存多个类型相同的数据.每种基本数据类型都有对应的Buffer类: 缓冲区 ...

  7. PostgreSQL Replication之第十一章 使用Skytools(5)

    11.5 关于walmgr 的介绍 walmgr 是一个简化基于文件事务日志传输的工具.早在过去的一些日子里(在9.0版本之前),使用walmgr来简化基本备份是很常见的.随着流复制的引入,情况有了一 ...

  8. java-语法

    JAVA语法 1.标识符 1.定义:对各种变量.方法.类等进行命名的字符序列 2.规则:他的组成由字母.数字.$,数字不能出现在开始,不能和关键字重复,区分大小写 2.数据类型 1.分类 1基本数据类 ...

  9. codevs 1204 寻找子串位置

    http://codevs.cn/problem/1204/ 1204 寻找子串位置  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 青铜 Bronze 题解  查看运行结果 ...

  10. 数据库SQL CRUD

    1.删除表 drop  table +表名 2.修改表 alter  table+表名+ add(添加)+列名+ int(类型) alter  table+表名+ drop(删除)+column(列) ...