在日常的运维工作中,对生产数据表进行DDL操作是一件需要谨慎对待的事情。运维DBA们在进行数据DDL操作的时候,通常要全局考虑,诸如对生产影响、执行时间长度和影响存储数据等等。
数据列默认值的添加,是DBA们经常头疼的一个问题。传统的执行语句,消耗时间长、资源使用量大,对生产环境影响程度高。采用其他的一些变通方法,又存在操作步骤繁琐的问题。如何快速的添加一个有默认值的数据列,同时对现有生产环境影响最小,是我们希望达到的一个目标。
本文从操作入手,探讨添加default数据列的问题点,最后介绍Oracle 11g中对其进行的“革命性”优化。
1、从10g的数据列添加谈起
为了实现对比效果,我们首选选择10g版本的Oracle进行试验,构造一个相对较大的数据表。
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
SQL> create table t as select object_id from dba_objects;
表已创建。
SQL> select count(*) from t;
COUNT(*)
----------
3220352
数据表t只包括一个数据列,但是数据量大约为320万条。我们从体积上进行评估如下:
SQL> set timing on;
SQL> select bytes/1024/1024,blocks from dba_segments where wner='SYS' and segment_name='T';
BYTES/1024/1024 BLOCKS
--------------- ----------
39 4992
已用时间: 00: 00: 00.03
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade=>true);
PL/SQL过程已成功完成。
已用时间: 00: 00: 00.35
SQL> select blocks from dba_tables where wner='SYS' and table_name='T';
BLOCKS
----------
4883
已用时间: 00: 00: 00.01
Oracle分配给这个段segment的中空间为4992个数据块,高水位线HWM下的格式化过数据块为4883。总体积约40M。
下面进行两种方式的添加数据表默认值列方法,一起观察一下变化情况。首先是允许为空默认值列的操作。
SQL> alter table t add vc varchar2(100) default 'TTTTTTTTTTTT';
表已更改。
已用时间: 00: 34: 37.15
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade=>true);
PL/SQL过程已成功完成。
已用时间: 00: 00: 03.86
SQL> select bytes/1024/1024,blocks from dba_segments where wner='SYS' and segment_name='T';
BYTES/1024/1024 BLOCKS
--------------- ----------
208 26624
已用时间: 00: 00: 00.06
SQL> select blocks from dba_tables where wner='SYS' and table_name='T';
BLOCKS
----------
25864
已用时间: 00: 00: 00.01
果然是一个费时的操作,添加一个数据列默认值,总共消耗了近30分钟时间。原有数据表的体积也发生的膨胀,从原来的不到40M,上升到了208M。
这个现象告诉我们,当我们添加一个有default值的数据列,并且是直接添加的时候,一些数据被插入到了数据块中,引起空间膨胀。
在原有的结构下,数据添加到数据块上是必需的,只有这样才能将数据列default添加到里面去。
除了这个字句,我们是还可以提供数据列的not null选项,也是可以实现相同的功能的。
SQL> alter table t add vc2 varchar2(100) default 'TTTTTTTTTTTT' not null;
表已更改。
已用时间: 00: 15: 58.85
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade=>true);
PL/SQL过程已成功完成。
已用时间: 00: 00: 36.87
SQL> select bytes/1024/1024,blocks from dba_segments where wner='SYS' and segme
nt_name='T';
BYTES/1024/1024 BLOCKS
--------------- ----------
256 32768
已用时间: 00: 00: 00.14
SQL> select blocks from dba_tables where wner='SYS' and table_name='T';
BLOCKS
----------
32448
已用时间: 00: 00: 00.04
也是消耗了15分钟,空间发生了很大程度变化。新空间分配,同时数据行数没有发生变化,潜在的行迁移(Row Migration)和行链接(Row Chaining)是严重恶化的!
综合分析Oracle 10g下的操作:为了添加上数据字段的默认值,Oracle会去访问每个数据块上的每个数据行进行数据列拓展工作,这个过程中还伴随着新空间分配和多余数据行复制。
这类型操作对于生产环境是恐怖的,在整个作业过程中,数据表结构被锁定,相关业务处理操作阻塞或者缓慢。所以,运维DBA都是选择在维护窗口或者变通的方法进行处理。
在Oracle 11g环境下,事情有了一些不同。
当前位置: 数据库>oracle
浅析Oracle 11g中对数据列默认值变化的优化
来源: 互联网 发布时间:2017-05-07
本文导语: 在日常的运维工作中,对生产数据表进行DDL操作是一件需要谨慎对待的事情。运维DBA们在进行数据DDL操作的时候,通常要全局考虑,诸如对生产影响、执行时间长度和影响存储数据等等。 数据列默认值的添加,是DBA们经常头疼...