两个小问题的实验拾零

 

Oracle有很多的知识细节,是需要我们平时敏于发现、勤于思考、善于积累的。这些知识看似零碎,但是是我们学习的一个重要方面。本篇权当记录两个有意思的实验。

 

1、远程对象依赖关系

 

在笔者之前的《从视图看Oracle对象依赖机制》(http://space.itpub.net/17203031/viewspace-718906)中,比较详细的介绍了Oracle中对象依赖的基本原理和启用失效机理。简单的说,Oracle内部会维护依赖对象关系,我们可以通过dba_dependencies查看到基本的依赖关系。当依赖链条上出现失效关系,连带的状态变化会连锁变化。

 

但是,一个问题出现了。连带关系是在一个数据库的内部进行。如果一个本地对象依赖的是通过dblink关系连到远程的一个对象,形成的依赖关系。这样还成立吗?

 

如果成立,也就是说如果远程对象变为invalid或者不存在,要通知到本地数据库知晓。个人感觉太神奇了些,做个实验去证明一下。

 

我们选择11g实验数据库。

 

 

SQL> select * from v$version;

 

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production

PL/SQL Release 11.2.0.1.0 - Production

CORE     11.2.0.1.0       Production

 

SQL> select dbid, name from v$database;

      DBID NAME

---------- ---------

2351142467 NBSTEST

 

SQL> show user;

User is "nbs"

 

 

我们首先在nbstest上,使用nbs用户登录。之后创建实验数据表t

 

 

SQL> create table t as select * from dba_objects where wner='NBS';

Table created

 

SQL> select count(*) from t;

  COUNT(*)

----------

       262

 

 

在另一个数据库nbsdev上,我们使用dblink连接到nbstest上。

 

 

SQL> select dbid, name from v$database;

      DBID NAME

---------- ---------

3162889288 NBSDEV

 

SQL> select object_name, object_type, status from dba_objects where object_name='NBS_TEST';

 

OBJECT_NAME          OBJECT_TYPE         STATUS

-------------------- ------------------- -------

NBS_TEST             DATABASE LINK       VALID

 

-- Create database link

create public database link NBS_TEST

  connect to NBS

  using 'nbstest';

 

 

nbsdev上创建视图,访问nbstest上的数据表t

 

 

SQL> select count(*) from t@nbs_test;

  COUNT(*)

----------

       262

 

SQL> create view v_t as select * from t@nbs_test;

View created

 

SQL> select count(*) from v_t;

  COUNT(*)

----------

       262

 

SQL> select count(*) from dba_dependencies where name='V_T';

  COUNT(*)

----------

         0

 

SQL> select object_name, object_type, status from dba_objects where object_name='V_T';

OBJECT_NAME          OBJECT_TYPE         STATUS

-------------------- ------------------- -------

V_T                  VIEW                VALID

 

 

注意上面的现象:我们建立了视图v_t,里面引用了nbstest上的数据表t,而且是通过本地的dblink。但是,我们没有在依赖关系中找到v_t对其他对象的任何关系依赖。这个与我们想法开始出现差异。

 

下面我们回来将t失效。

 

 

SQL> conn nbs/xxx@nbstest;

Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.1.0

Connected as nbs

 

SQL> drop table t;

Table dropped

 

 

但是,nbstest上的v_t依赖状态不变,依然是valid状态。

 

 

SQL> select dbid, name from v$database;

      DBID NAME

---------- ---------

3162889288 NBSDEV

 

SQL> select object_name, object_type, status from dba_objects where object_name='V_T';

OBJECT_NAME          OBJECT_TYPE         STATUS

-------------------- ------------------- -------

V_T                  VIEW                VALID

 

--确实是失效了;

SQL> select count(*) from v_t;

select count(*) from v_t

 

ORA-00942: 表或视图不存在

ORA-02063: 紧接着 line (起自 NBS_TEST)

 

SQL> select object_name, object_type, status from dba_objects where object_name='V_T';

OBJECT_NAME          OBJECT_TYPE         STATUS

-------------------- ------------------- -------

V_T                  VIEW                VALID

 

 

即使我们将t删除,即使我们重新使用了v_t而且报错,v_t的状态依然是valid结论:oracle对象依赖关系对远程对象依赖关系,是一个“松连接”。依赖关系是不会连带影响到远程对象的有效性的。

 

那么,对于本地的dblink对象,Oracle是否会保证呢?我们继续进行实验。

 

--恢复状态

SQL> select object_name, object_type, status from dba_objects where object_name='V_T';

OBJECT_NAME          OBJECT_TYPE         STATUS

-------------------- ------------------- -------

V_T                  VIEW                VALID

 

SQL> select count(*) from v_t;

  COUNT(*)

----------

       262

 

--最后一的关系对象dblink

SQL> drop public database link NBS_TEST;

Database link dropped

 

SQL> select object_name, object_type, status from dba_objects where object_name='V_T';

OBJECT_NAME          OBJECT_TYPE         STATUS

-------------------- ------------------- -------

V_T                  VIEW                VALID

 

 

结论:看来Oracle对于涉及到远程连接的内容,都是不纳入到依赖关系列表的。

 

2Truncate回收空间失效

 

这个问题是源自QQ群一个朋友的问题。我们都知道truncate table是一个典型的ddl语句。对一个数据表进行truncate操作,意味着数据快速删除、空间快速回收、高水位线降低。通常情况下,我们进行truncate操作后,数据表会恢复到一个extent大小。注意:truncate操作是不会影响到头块地址的。如下面的简单实验:

 

 

SQL> create table t as select * from dba_objects;

Table created

 

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

 

 

SQL> select HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS, EXTENTS, INITIAL_EXTENT, MIN_EXTENTS  from dba_segments where wner='SYS' and segment_name='T';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS INITIAL_EXTENT MIN_EXTENTS

----------- ------------ ---------- ---------- ---------- -------------- -----------

     1        63081    6291456        768         21          65536           1

 

 

此时,Oracle分配21个分区,768个数据块。进行truncate操作。

 

 

SQL> truncate table t;

Table truncated

 

SQL> select HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS, EXTENTS, INITIAL_EXTENT, MIN_EXTENTS  from dba_segments where wner='SYS' and segment_name='T';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS INITIAL_EXTENT MIN_EXTENTS

----------- ------------ ---------- ---------- ---------- -------------- -----------

     1        63081      65536          8          1          65536           1

 

 

truncate之后,数据段恢复到1个分区大小。

 

那么,是不是所有的情况都是如此呢?QQ提问的那个朋友就遇到了这样的情况。

 

 

--恢复空间

 

SQL> select count(*) from t_ba;

 

  COUNT(*)

----------

     50688

 

SQL> select HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS  from dba_segments where wner='SYS' and segment_name='T_BA';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

----------- ------------ ---------- ----------

          1        64137   20971520       2560

 

--Truncate Table 操作

SQL> truncate table t_ba;

Table truncated

 

SQL> select HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS,extents  from dba_segments where wner='SYS' and segment_name='T_BA';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

----------- ------------ ---------- ---------- ----------

          1        64137   20971520       2560         20

 

SQL> select count(*) from t_ba;

 

  COUNT(*)

----------

         0

 

 

根据字典信息,数据表T_BA大小没有变化,空间没有回收,高水位线没有完全下降到一个分区大小。但是数据已经没有了。

 

按照我们的经验,truncate意味着空间的快速回收,应该不会保留如此多的数据extents。问题出现在哪里呢?我们检查一下数据字典。

 

 

SQL> select HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS, EXTENTS, INITIAL_EXTENT, MIN_EXTENTS  from dba_segments where wner='SYS' and segment_name='T_BA';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS INITIAL_EXTENT MIN_EXTENTS

----------- ------------ ---------- ---------- ---------- -------------- -----------

          1        64137   20971520       2560         20       19988480           1

 

 

注意init_extents取值,19988480不是我们常见的数据表初始化取值。的确笔者在此处进行了处理,下面是处理语句。

 

 

SQL> alter table t storage (minextents 20);

alter table t storage (minextents 20)

 

ORA-25150: 不允许对区参数执行 ALTERING

 

SQL> create table t_ba storage (minextents 20) as select * from t;

Table created

 

 

我们在创建数据表的时候,storage子句集合中minextents参数一般是选择默认值1,也就是我们经常truncate回缩的大小。但是如果我们在建表(也只能在建表时),指定一个不同的取值,那么数据段就会保持这个大小。即使在使用truncate操作。

 

下一个问题是,我们一般在创建数据表的时候,是不会轻易设置这个取值的。那么为什么我们的系统中还会出现这种情况呢?我们说,这个是由于一些脚本抽取、数据备份工具的副作用引起的。

 

当我们使用一些备份还原工具的时候,在提取数据DDL阶段,会将当前数据段大小作为初始段空间分配。这样,导入数据所需要段空间就是创建段的时候被分配好了,这样进行数据插入的时候,可以避免频繁的进行空间分配操作。应该说,这是一种优化策略。

 

但是,这样的数据表在truncate或者其他一些空间收缩操作的时候,就遇到了麻烦,就是始终是一个很大的数据段。

 

了解了原因,问题就很好解决。可以通过数据表重构、空间重新分配等方式进行调节。但是,从笔者的角度出发,认为调节操作应慎重:

 

ü        确定进行空间回收的目的。膨大的init_extents起码表示曾经该数据表达到过某一个大小。正常业务场景下,数据量可能就是维持一个稳定值。如果只是因为当前我们暂时性的表被清空,或者数据减少,过一段时间后还会回到原有大小。那么,进行调整的意义真不是很大;

ü        如果确定需要暂时性的回收空间,或者业务确实发生变化,可以进行这个操作。

 

3、结论

 

上述两个小知识点,权当拾遗。记录下来,供有需要的朋友应急。

 

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-721987/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/17203031/viewspace-721987/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值