【引言】
今天有同事问了一个问题,在Oracle 11g下,为啥exp方式导出一个用户的数据表,在imp后却发现有些表并没有迁移过来。经查阅官方文档,发现和Oracle11g及12c +版本相对于10g,有一个新特性deferred_segment_creation(延迟段创建)造成的。
该参数的作用为:
oracle11g中当创建的表无数据时,不进行segment分配,以节省存储空间。
为了理解啥原理,这里再复习下Oracle的几个概念:
-
tablespace: 一个数据库划分为一个或多个逻辑单位,该逻辑单位成为表空间;每一个表空间可能包含一个或多个Segment;
-
Segments: Segment指在tablespace中为特定逻辑存储结构分配的空间。每一个段是由一个或多个extent组成。包括数据段、索引段、回滚段和临时段。
-
Extents: 一个 extent 由一系列连续的 Oracle blocks 组成。通过extent 来给segment分配空间。
-
Data Blocks:Oracle 最小I/O存储单位,一个 data block 对应一个或多个分配给data file的操作系统块;默认为8KB,此参数在创建实例时可以修改,如做数仓库一般修改为64KB以上,为的是一次能从存储中多读取一些数据进内存,提升处理速度。
来张图更直观:
Oracle10g之前的版本,table 创建时,默认创建了一个data segment,这个data segment含有min extents 指定的extents 数,每个extent 据据表空间的存储参数分配一定数量的blocks。
Oracle11g及12c以后版本,有了一个新特性参数deferred_segment_creation(延迟段创建),默认为true;该参数表示:创建表时,如为空没有数据插入则不分配segment,如果为false,则在创建表示创建一个data segment;
注意sys用户除外,它会自动分配空间,普通用户不会自动创建。
了解了如上deferred_segment_creation特性;
有同学会说:把deferred_segment_creation修改为flase不就行了。
注意:
deferred_segment_creation修改为flase后,只对新建的空表起作用,之前空表依旧无法正常导出,除非把之前的所有空表做一次segment段分配处理。
怎么做?
把所有的空表做segment create 处理,通过sql手动方法实现。
步骤如下:
步骤1:–查询所有的空表
select table_name from user_tables where NUM_ROWS=0;
步骤2:–拼接sql,批量生成修改语句
select ‘alter table ‘||table_name||’ allocate extent;’ from user_tables where num_rows=0;
步骤3:–利用exp/imp命令重新执行导出和导入操作即可。
步骤4:–修改deferred_segment_creation修改为flase,规避后续再次出现此类问题。
这里注意,步骤2会出现一种现象:
步骤2查出来的有些空表,在视图user_tables中的num_rows不等于0(原因:表中以前有数据,删除后oracle没有统计,视图user_tables中数据没有更新),故通过步骤2的sql并不能为所有的空表分配数据段。
怎么办?
执行一遍统计信息搜集即可。
select ‘analyze table ‘||table_name||’ compute statistics;’ from user_tables;
analyze table tablename compute statistics;
等同于 analyze table tablename compute statistics for table for all indexes for all columns;
for table的统计信息存在于视图:user_tables 、all_tables、dba_tables
for all indexes的统计信息存在于视图:user_indexes 、all_indexes、dba_indexes
for all columns的统计信息存在于试图:user_tab_columns、all_tab_columns、dba_tab_columns
执行完后,视图user_tables中的num_rows值会做更新,此时再执行步骤2,能够给所有空表分配数据段
然而,在执行 analyze table tablename compute statistics 时,oracle会报object statictis are locked (这些表的统计被锁了),通过如下方式解锁:
select ‘exec dbms_stats.unlock_table_stats(’||’’‘OWNNAME’’’||’,’’’||table_name||’’’);’ from user_tables where table_block=’DISABLED’;
以下是UNLOCK_TABLE_STATS Procedure介绍
欢迎关注个人微信公众号“一森咖记”