浅析Oracle 11g中对数据列默认值变化的优化

日常的运维工作中,对生产数据表进行DDL操作是一件需要谨慎对待的事情。运维DBA们在进行数据DDL操作的时候,通常要全局考虑,诸如对生产影响、执行时间长度和影响存储数据等等。 数据列默认值的添加,是DBA们经常头疼的一个问题。传统的执行语句,消耗时间

在日常的运维工作中,对生产数据表进行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环境下,事情有了一些不同。

2、11g下的默认值配置

我们在11g上进行相似操作。

SQL> select * from v$version;
BANNER
——————————————————————————–
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 – Production

PL/SQL Release 11.2.0.1.0 – Production
CORE       11.2.0.1.0        Production

构建相似规模的数据表。

SQL> set timing on;
SQL> create table t as select object_id from dba_objects;
Table created

SQL> select count(*) from t;
COUNT(*)
———-
  3323167

SQL> exec dbms_stats.gather_table_stats(user,’T’,cascade => true);
PL/SQL procedure successfully completed

SQL> select segment_name, bytes/1024/1024, extents,blocks from user_segments where segment_name=’T’;

SEGMENT_NA BYTES/1024/1024   EXTENTS    BLOCKS
———- ————— ———- ———-
T                      40        55      5120

SQL> select NUM_ROWS, BLOCKS from dba_tables where wner=’SCOTT’ and table_name=’T’;

NUM_ROWS    BLOCKS
———- ———-
  3323167      5041

11g下我们准备了约330万数据,进行添加非空带默认值的数据列。

SQL> alter table t add vc2 varchar2(100) default ‘TTTTTTTTTTTT’ ;

alter table t add vc2 varchar2(100) default ‘TTTTTTTTTTTT’

ORA-01013:用户请求取消当前的操作

在添加defalut列,不指定not null的时候,数据持续时间超过了我们的想象。笔者主动将其断开了。下面试试添加not null时候。

–1s不到完成操作;
SQL> alter table t add vc varchar2(100) default ‘TTTTTTTTTTTT’ not null;
Table altered

Executed in 0.047 seconds

SQL> exec dbms_stats.gather_table_stats(user,’T’,cascade => true);
PL/SQL procedure successfully completed

SQL> select NUM_ROWS, BLOCKS from dba_tables where wner=’SCOTT’ and table_name=’T’;
NUM_ROWS    BLOCKS
———- ———-
  3323167      5041

Executed in 0 seconds

SQL> select segment_name, bytes/1024/1024, extents,blocks from user_segments where segment_name=’T’;

SEGMENT_NA BYTES/1024/1024   EXTENTS    BLOCKS
———- ————— ———- ———-
T                      40        55      5120

SQL> select * from t where rownum

OBJECT_ID VC
———- ——————————————————————————–
       20 TTTTTTTTTTTT
       46 TTTTTTTTTTTT
       28 TTTTTTTTTTTT
       15 TTTTTTTTTTTT
(篇幅原因,有省略……)
9 rows selected

我们发现,当执行not null的时候,Oracle以超乎想象的速度完成了过程。并且注意:数据表的体积没有发生任何变化!!但是,我们检查数据表的时候,却发现了对应列的默认值已经添加。

这个事情是比较奇怪的,有一个道理必然是可以说通:就是这个默认值在执行过程中,是绝对没有真正添加到数据块中的,因为只有这样才不会影响数据段的体积。

3、11g默认值处理的优化

那么,11g这个过程中是如何处理的呢?而且为什么只有添加Not null的时候才会有这个特点。我们从select数据行的trace进行入手。

我们选择10046跟踪一下select的全过程,看看显示出来的默认值从哪里来。

SQL> select value from v$diag_info where name=’Default Trace File’;

VALUE
———————————————————————–
/u01/diag/rdbms/wilson/wilson/trace/wilson_ora_6177.trc

SQL> alter session set events ‘10046 trace name context forever, level 12’;
会话已更改。

SQL> select * from t where rownum

OBJECT_ID
———-
VC
—————————————————————————–

SQL> alter session set events ‘10046 trace name context off’;
会话已更改。

对生成的trace文件进行处理,获取到tkprof结果。

D:\des>tkprof wilson_ora_6177.trc
output = res.txt

TKPROF: Release 10.2.0.1.0 – Production on星期五8月24 22:07:10 2012
Copyright (c) 1982, 2005, Oracle. All rights reserved.

在分析的结果中,我们发现很多的recursive语句,也就是Oracle为了执行这个SQL,连带运行了很多的语句,其中我们发现了一个“可疑”对象。

***********************************************************************

select binaryDefVal, length(binaryDefVal)
from
ecol$          where tabobj# = :1 and colnum = :2

call    count      cpu   elapsed      disk     query   current       rows
——- —— ——– ———- ———- ———- ———- ———-
Parse       1     0.00      0.00         0         0         0          0
Execute     1     0.00      0.00         0         0         0          0
Fetch       1     0.00      0.00         2         2         0          1
——- —— ——– ———- ———- ———- ———- ———-
total       3     0.00      0.00         2         2         0          1

ecol$是sys用户下的一个新添加的字典基表,其中内容如下:

SQL> desc ecol$;
Name        Type  Nullable Default Comments
———— —— ——– ——- ——–
TABOBJ#     NUMBER Y                       
COLNUM      NUMBER Y                       
BINARYDEFVAL BLOB  Y                       

SQL> select * from ecol$;

  TABOBJ#    COLNUM BINARYDEFVAL
———- ———- ————
    76046         2
Executed in 0.031 seconds

SQL> col owner for a10;
SQL> col object_name for a10;
SQL> select owner, object_name, object_id from dba_objects where object_id in (76046);

OWNER     OBJECT_NAM OBJECT_ID
———- ———- ———-
SCOTT     T              76046

Executed in 0 seconds

从ecol$数据表中,我们发现了对数据表T对象第二列(column=2)的一个对象引用,引用的值binarydefval是一个blob类型。从直观上,我们已经可以猜出这个就是记录了数据表vc列的默认值。

此处,我们说一个问题,在Oracle中,默认值都是通过大对象类型进行保存。在数据字典col$中,默认值是通过long类进行保存。而进入11g的ecol$表,这个值是使用blob类型进行保存。

另一个需要注意的,就是这个数据表中只有一个数据行,也就是只有我们创建数据表T的默认值。这说明什么呢?

此时,我们已经可以猜出Oracle的良苦用心。首先,Oracle注意到了在生产online的时候,添加带默认值列数据的困难。但是,从现有的体系结构和存储结构下,将默认值逐行插入、从而引起行迁移的情况是不能避免的。所以,Oracle采用了一种“障眼法”。

如果我们在创建数据表的时候就指定了数据列的默认值、或者没有要求将所有数据空值一次性全都变成默认值的时候,Oracle还是按照原有的存储策略进行管理。如果出现了要求添加数据列,并且一次性将所有默认值列都加入的情况,Oracle索性就不进行插入数据和挪行的操作,而是将这个默认值保存在ecol$中。

接下来,如果要进行检索数据,首先Oracle会利用recursive call的方法,保存提取出默认值。在检索数据的过程中,如果遇到默认值列为空的情况(没有插值),就将取出的默认值输出到界面上进行显示。其实,数据行对应的默认值列是没有这个值的。

这就解释了为什么只有在添加not null默认值列的时候,才会有这个优化。因为Oracle需要确认这个列不会有空值,才会将出现的空值全都进行“障眼法”匹配。

4、结论

借助了11g这个特性,我们说在online生产环境下,临时加入默认值列就不是一件恐怖的工作了。不过,处于谨慎的考虑,还是希望有条件的时候,将该数据表进行重构。这种特性属于应急环境下考虑使用。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/467102.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月8日 05:52:10
下一篇 2025年11月8日 05:54:54

相关推荐

  • Oracle DATE 类型存储时间戳及如何仅存储日期

    本文旨在解释 Oracle 数据库中 DATE 类型总是包含时间戳的原因,并提供在数据库中存储日期时去除时间部分的方法,重点介绍如何通过格式化函数控制日期显示,而非修改数据库结构。 在 Oracle 数据库中,DATE 类型的设计初衷就是同时存储日期和时间信息。即使你只关心日期部分,DATE 类型仍…

    2025年12月6日 java
    000
  • mysql中事务隔离级别有哪些

    读未提交允许读取未提交数据,易引发脏读、不可重复读和幻读;2. 读已提交确保读取已提交数据,避免脏读但存在不可重复读和幻读;3. 可重复读保证事务内多次读取一致,MySQL默认级别,通过MVCC和间隙锁减少幻读;4. 串行化强制事务串行执行,避免所有并发问题但性能最差。选择隔离级别需权衡一致性与性能…

    2025年12月6日 数据库
    000
  • 优化MySQL电话号码字段搜索:解决空格与格式多样性问题

    本文详细介绍了在mysql数据库中,如何高效地搜索包含空格或多种格式的电话号码字段。针对`like`查询无法识别空格字符的问题,核心解决方案是利用`replace`函数在查询时移除字段中的空格,从而实现准确匹配。教程还将探讨更全面的数据清洗策略和性能优化建议,以提升搜索效率和数据质量。 在数据库管理…

    2025年12月6日 后端开发
    000
  • OpenJPA 在 Oracle 中处理字符串长度限制的警告与解决方案

    本文深入探讨了 openjpa 在与 oracle 数据库交互时,针对字符串字段可能遇到的“值超过 4000 字节/字符”的警告信息。该警告源于 oracle `varchar2` 数据类型的默认 4000 字节限制。教程将详细介绍两种主要的解决方案:通过 `@column(length = n)`…

    2025年12月6日 java
    000
  • Java中MANIFEST.MF的作用 详解清单文件

    manifest.mf是java中jar文件的元数据配置文件,位于meta-inf目录下,用于定义版本、主类、依赖路径等关键信息。1. 它允许指定入口类,使jar可直接运行;2. 通过class-path管理依赖,减少类加载冲突;3. 可配置安全权限,如设置沙箱运行;4. 常见属性包括manifes…

    2025年12月5日 java
    000
  • Java中枚举类型怎么定义 掌握Java枚举的定义和常用方法

    java中定义枚举类型使用enum关键字,例如public enum weekday { monday, tuesday,…};枚举可包含字段和方法,如添加中文名称字段及获取方法;可在switch语句中使用,确保覆盖所有值;常用方法包括values()、valueof()、ordinal…

    2025年12月4日 java
    000
  • oracle/mysql拼接值遇到的坑及双竖线||和concat怎么使用

    %ign%ignore_a_1%re_a_1% mysql 拼接值遇到的坑 双竖线 || concat || “||” 在oracle中是拼接值,但在mysql中是“或”的意思。 where name like ‘%’ || ‘Tony’ || ‘%’ 所以推荐使用concat() concat()…

    数据库 2025年12月4日
    000
  • 台积电决定两年内逐步退出 6 英寸晶圆制造,持续整并 8 英寸晶圆产能

    8 月 12 日消息,台积电今日举行新一期董事会。公司宣布,为优化组织运营并提升整体运作效率,经全面评估后决定在未来两年内逐步终止 6 英寸晶圆的生产制造,并持续推进 8 英寸晶圆产能的整合,以强化运营效益。 台积电强调,此项调整是基于对市场趋势与长期发展战略的综合考量。目前公司正与客户密切协作,确…

    2025年12月4日
    000
  • Linux实现自动挂载autofs的方法详解

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 目录 实现自动挂载-autofs autofs工具简单使用 autofs配置详细说明 自动挂载资源有两种格式 优化Linux系统性能 安装Tuned 选择调整配置文件 检查系统推荐的调整配置文件…

    2025年12月4日
    000
  • 简易项目搭建(用于一般杂七杂八的小功能点)

    在工作中,我们常常会遇到许多需要完成的小功能点。以我自己的工作情况为例,最常见的是两个方面:1、控制台项目;2、web界面(纯前端)。 首先让我们讨论控制台项目的工作内容。在没有使用PostMan之前,工作中大量使用接口调用。在项目准备阶段,首先需要对接口的使用进行描述。在主要使用WebServic…

    2025年12月4日
    000
  • 分页功能如何实现?LIMIT与页码计算

    分页功能通过offset和limit截取数据实现。1.分页核心是计算偏移量(offset=(页码-1)每页条数)和限制数量;2.使用sql的limit子句或数据库特定语法(如sql server的offset…fetch next)执行查询;3.前端传页码和每页大小,后端计算偏移量并执行…

    2025年12月3日 后端开发
    000
  • Java中DAO模式的作用 解析DAO模式封装数据访问的价值

    dao模式通过解耦业务逻辑与数据访问,解决了数据库切换困难、sql注入风险和代码重复问题。其核心价值在于将数据访问细节封装在接口和实现类中,使业务代码仅面向接口编程,从而降低维护成本。具体步骤包括:1.定义dao接口;2.创建具体实现类;3.使用工厂模式获取实例;4.在业务逻辑中调用dao方法。技术…

    2025年12月3日 java
    000
  • Swoole如何做数据加密?加密算法如何选择?

    Swoole中数据加密依赖PHP的OpenSSL扩展,通过选择AES、RSA等算法实现;在Server或Client的接收与发送过程中进行加解密操作,结合CBC、GCM等模式保障安全与性能;密钥应通过环境变量或配置文件管理,避免硬编码;为防止中间人攻击,应启用TLS/SSL加密通信,并在WebSoc…

    2025年12月3日
    100
  • Swoole如何实现多租户?租户隔离怎么操作?

    Swoole实现多租户的核心在于协程上下文隔离,通过Coroutine::getContext()绑定租户ID、数据库连接、缓存前缀等上下文信息,在请求入口识别租户并加载配置,确保数据、缓存、文件存储、数据库连接等资源按租户隔离,避免长驻内存导致的数据泄露,结合连接池重置、缓存键前缀、独立表或库等策…

    2025年12月3日
    000
  • 2023合同管理软件排名:前10名榜单

    合同管理软件依托信息技术,结合现代企业的先进管理思想,为企业构建起一个集决策、规划、控制及经营绩效评估于一体的全方位、系统化的管理平台。企业在开展经济活动时,通常以合同为纽带,合同管理的效果直接关系到经营的成败。作为企业管理的重要组成部分,合同管理对业务流程的规范化、数据的准确性以及信息传递的安全性…

    2025年12月3日 软件教程
    000
  • 如何在PHP中配置Oracle数据库连接池的详细教程?

    在php中配置oracle数据库连接池需依赖oracle工具和配置,而非php本身。1. 安装oracle instant client并配置环境变量,安装oci8扩展并在php.ini中启用;2. 在oracle端启用drcp连接池,使用dbms_connection_pool包启动并调整参数;3…

    2025年12月3日 后端开发
    000
  • 零基础学Java课程安排建议

    it行业目前非常热门,对于大学生而言,若想在大学期间学习java但又毫无基础,以下是一份适合的课程学习流程推荐: 1、 公共基础知识:初步了解计算机网络和数据结构的基础内容,掌握基本概念即可。 2、 Java基础课程大约需要三周时间完成,建议从视频教程开始学习。学完后可以在网上找一套系统的练习题进行…

    2025年12月3日 软件教程
    000
  • Windows2003系统下MySQL安装小结

    本文承接上文在windows2003系统中配置支持php的tomcat网站内容继续进行说明。 1、 支持列表中并未列出Windows 2003版本。 2、 我下载了社区版5.7.22,但在安装过程中提示“mysqld不是有效的Win32应用程序”,令人费解。 3、 随后选择降低版本,改用5.6.40…

    2025年12月3日 软件教程
    000
  • Oracle视图应用实战

    1、 在Oracle数据库中创建视图,并通过查询语句获取视图中的数据内容。 2、 对已存在的Oracle视图进行结构或定义修改,并执行重新编译以确保其有效性。 3、 %ignore_a_1%览当前数据库中存在的视图列表,并根据需要删除指定的视图对象。 4、 执行对Oracle视图的数据查询操作,同时…

    2025年12月3日 软件教程
    000
  • sql中如何实现递归查询 递归查询的经典案例演示

    sql递归查询通过cte实现层级数据查询,核心在于锚点成员与递归成员结合,常见错误包括无限循环、性能问题、数据类型不匹配等;优化方法有索引优化、限制递归深度、使用临时表等;不同数据库如postgresql、sql server、mysql支持递归cte,oracle则使用connect by语法。 …

    2025年12月3日 数据库
    000

发表回复

登录后才能评论
关注微信