ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 数据文件RESIZE导致查询DBA_DATA_FILES被锁

数据文件RESIZE导致查询DBA_DATA_FILES被锁

原创 Linux操作系统 作者:yangtingkun 时间:2010-12-17 23:49:35 0 删除 编辑

在客户的服务器上发现一个现象,执行对DBA_DATA_FILES的查询被挂起。检查发现是由于这时数据文件正在执行RESIZE操作。

 

 

这个现象在9i10g11g中都能重现,下面是9i一个测试环境下的问题重现,这个数据库很简单,只包括了两个数据文件:

SQL> select file_name, file_id, tablespace_name, bytes, blocks 
  2  from dba_data_files;

FILE_NAME                              FILE_ID TABLESPACE_NAME      BYTES     BLOCKS
----------------------------------- ---------- --------------- ---------- ----------
/data/oradata/test9/system01.dbf             1 SYSTEM          1.0737E+10    1048576
/data/oradata/test9/test01.dbf               2 TEST            2147491840     209716

操作分为三个会话进行,会话1准备执行表空间的RESIZE操作:

SQL> set timing on
SQL> alter database datafile '/data/oradata/test9/test01.dbf' resize 10240m;

数据库已更改。

已用时间:  00: 00: 55.78

随后会话2先运行对V$DATAFILE视图的查询,然后对DBA_DATA_FILES视图进行查询:

SQL> set sqlp 'SQL2> '
SQL2> select sid from v$mystat where rownum = 1;

       SID
----------
        10

SQL2> set timing on
SQL2> select file#, ts#, rfile#, name, bytes, blocks
  2  from v$datafile;

     FILE#        TS#     RFILE# NAME                                     BYTES     BLOCKS
---------- ---------- ---------- ----------------------------------- ---------- ----------
         1          0          1 /data/oradata/test9/system01.dbf    1.0737E+10    1048576
         2          2          2 /data/oradata/test9/test01.dbf      2147491840     209716

已用时间:  00: 00: 00.00
SQL2> select file_name, file_id, tablespace_name, bytes, blocks        
  2  from dba_data_files;

FILE_NAME                              FILE_ID TABLESPACE_NAME      BYTES     BLOCKS
----------------------------------- ---------- --------------- ---------- ----------
/data/oradata/test9/system01.dbf             1 SYSTEM          1.0737E+10    1048576
/data/oradata/test9/test01.dbf               2 TEST            1.0737E+10    1048576

已用时间:  00: 00: 53.36

等会话2出现等待后,会话3检查会话2的等待事件:

SQL> set sqlp 'SQL3> '
SQL3> select seq#, event, p1, p2, p3, seconds_in_wait
  2  from v$session_wait
  3  where sid = 10;

      SEQ# EVENT                                  P1         P2         P3 SECONDS_IN_WAIT
---------- ------------------------------ ---------- ---------- ---------- ---------------
        90 row cache lock                          6          0          3              13

显然会话2一直等待到会话1结束还完成查询操作,而一般来说查询很少会被锁住。而且奇怪的是查询V$DATAFILE并不会被锁,而查询DBA_DATA_FILES视图则被锁住。根据会话3的运行结果,会话2的查询等待事件为row cache lock

显然问题很简单,只需要分析V$DATAFILEDBA_DATA_FILES两个视图的区别就可以找到原因所在:

SQL> select text from dba_views where view_name = 'DBA_DATA_FILES';

TEXT
--------------------------------------------------------------------------------
select v.name, f.file#, ts.name,
       ts.blocksize * f.blocks, f.blocks,
       decode(f.status$, 1, 'INVALID', 2, 'AVAILABLE', 'UNDEFINED'),
       f.relfile#, decode(f.inc, 0, 'NO', 'YES'),
       ts.blocksize * f.maxextend, f.maxextend, f.inc,
       ts.blocksize * (f.blocks - 1), f.blocks - 1
from sys.file$ f, sys.ts$ ts, sys.v$dbfile v
where v.file# = f.file#
  and f.spare1 is NULL
  and f.ts# = ts.ts#
union all
select
       v.name,f.file#, ts.name,
       decode(hc.ktfbhccval, 0, ts.blocksize * hc.ktfbhcsz, NULL),
       decode(hc.ktfbhccval, 0, hc.ktfbhcsz, NULL),
       decode(f.status$, 1, 'INVALID', 2, 'AVAILABLE', 'UNDEFINED'),
       f.relfile#,
       decode(hc.ktfbhccval, 0, decode(hc.ktfbhcinc, 0, 'NO', 'YES'), NULL),
       decode(hc.ktfbhccval, 0, ts.blocksize * hc.ktfbhcmaxsz, NULL),
       decode(hc.ktfbhccval, 0, hc.ktfbhcmaxsz, NULL),
       decode(hc.ktfbhccval, 0, hc.ktfbhcinc, NULL),
       decode(hc.ktfbhccval, 0, hc.ktfbhcusz * ts.blocksize, NULL),
       decode(hc.ktfbhccval, 0, hc.ktfbhcusz, NULL)
from sys.v$dbfile v, sys.file$ f, sys.x$ktfbhc hc, sys.ts$ ts
where v.file# = f.file#
  and f.spare1 is NOT NULL
  and v.file# = hc.ktfbhcafno
  and hc.ktfbhctsn = ts.ts#


SQL> select view_definition from v$fixed_view_definition where view_name = 'GV$DATAFILE';

VIEW_DEFINITION
--------------------------------------------------------------------------------------------
select fe.inst_id,fe.fenum,to_number(fe.fecrc_scn), to_date(fe.fecrc_tim,'MM/DD/RR HH24:MI:SS','NLS_CALENDAR=Gregorian')
, fe.fetsn,fe.ferfn, decode(fe.fetsn,0,decode(bitand(fe.festa,2),0,'SYSOFF','SYSTEM'),   decode(bitand(fe.festa,18),0,'O
FFLINE',2,'ONLINE','RECOVER')), decode(fe.fedor,2,'READ ONLY',   decode(bitand(fe.festa, 12),     0,'DISABLED',4,'READ O
NLY',12,'READ WRITE','UNKNOWN')), to_number(fe.fecps), to_date(fe.fecpt,'MM/DD/RR HH24:MI:SS','NLS_CALENDAR=Gregorian'),
 to_number(fe.feurs), to_date(fe.feurt,'MM/DD/RR HH24:MI:SS','NLS_CALENDAR=Gregorian'), to_number(fe.fests), decode(fe.f
ests,NULL,to_date(NULL),  to_date(fe.festt,'MM/DD/RR HH24:MI:SS','NLS_CALENDAR=Gregorian')), to_number(fe.feofs),to_numb
er(fe.feonc_scn), to_date(fe.feonc_tim,'MM/DD/RR HH24:MI:SS','NLS_CALENDAR=Gregorian'), fh.fhfsz*fe.febsz,fh.fhfsz,fe.fe
csz*fe.febsz,fe.febsz,fn.fnnam, fe.fefdb,fn.fnbof,                                              decode(fe.fepax, 0    ,
'UNKNOWN'                                              , 65535, 'NONE'
      , fnaux.fnnam)                            from x$kccfe fe, x$kccfn fn, x$kccfn fnaux, x$kcvfh fh          where
                                                            ((fe.fepax!=65535 and fe.fepax!=0 and fe.fepax=fnaux.fnnum)
             or   ((fe.fepax=65535 or fe.fepax=0) and fe.fenum=fnaux.fnfno                      and fnaux.fntyp=4 and fn
aux.fnnam is not null and fnaux.fnfno=fh.hxfil       and fe.fefnh=fnaux.fnnum))
    and fn.fnfno=fe.fenum and fn.fnfno=fh.hxfil and fe.fefnh=fn.fnnum            and fe.fedup!=0 and fn.fntyp=4 and fn.f
nnam is not null

可以看到,V$DATAFILE视图由4X$开头内部表构成:x$kccfex$kccfnx$kccfnx$kcvfh。访问这个视图可以马上返回结果。

DBA_DATA_FILES视图由两部分构成,第一部分包括file$ts$v$dbfile,而第二部分也包括这三个cluster表,同时还包括了一个X$开头的内部表:x$ktfbhc

通过进一步的分解测试,发现问题出现在x$ktfbhc这个对象上。通过分析DBA_DATA_FILES视图的定义,发现UNION ALL的两部分查询分别对应数据字典管理表空间和本地管理表空间,测试发现对数据字典管理的表空间执行RESIZE并不会导致查询视图被挂起:

SQL> select tablespace_name, extent_management
  2  from dba_tablespaces;

TABLESPACE_NAME                EXTENT_MAN
------------------------------ ----------
SYSTEM                         DICTIONARY
TEMP                           LOCAL
TEST                           LOCAL

SQL> set timing on
SQL> alter database datafile '/data/oradata/test9/system01.dbf' resize 1024m;

数据库已更改。

已用时间:  00: 00: 06.48

在会话2随后执行查询:

SQL2> select file_name, file_id, tablespace_name, bytes, blocks              
  2  from dba_data_files;

FILE_NAME                              FILE_ID TABLESPACE_NAME      BYTES     BLOCKS
----------------------------------- ---------- --------------- ---------- ----------
/data/oradata/test9/system01.dbf             1 SYSTEM          1073745920     104858
/data/oradata/test9/test01.dbf               2 TEST            1.0737E+10    1048576

已用时间:  00: 00: 00.01

RESIZE操作运行事件超过了6秒,但是查询瞬间就完成了。

看来问题和本地管理表空间的特性有关,对比查询file$x$ktfbhc的结果:

SQL> select file#, blocks, blocks * (select blocksize from ts$ where ts# = a.ts#) bytes
  2  from file$ a;

     FILE#     BLOCKS      BYTES
---------- ---------- ----------
         1     104858 1073745920
         2     209716 2147491840

已用时间:  00: 00: 00.00
SQL> select ktfbhcafno,
  2  decode(hc.ktfbhccval, 0, hc.ktfbhcsz, NULL) blocks,
  3  decode(hc.ktfbhccval, 0, ts.blocksize * hc.ktfbhcsz, NULL) bytes
  4  from sys.x$ktfbhc hc, sys.ts$ ts
  5  where hc.ktfbhctsn = ts.ts#;

KTFBHCAFNO     BLOCKS      BYTES
---------- ---------- ----------
         2    1048576 1.0737E+10

SQL> select file_name, file_id, tablespace_name, bytes, blocks        
  2  from dba_data_files;

FILE_NAME                              FILE_ID TABLESPACE_NAME      BYTES     BLOCKS
----------------------------------- ---------- --------------- ---------- ----------
/data/oradata/test9/system01.dbf             1 SYSTEM          1073745920     104858
/data/oradata/test9/test01.dbf               2 TEST            1.0737E+10    1048576

已用时间:  00: 00: 00.00

显然file$中记录的信息对于本地管理表空间是不正确的,事实上也不是结果不正常,而是这个视图记录的是文件创建时的大小。而一旦数据文件大小发生变化,就只能从x$ktfbhc中获取文件真正的大小了。

查询了一下这个内部视图的含义,这个对象是Kernel Tablespace File Bitmap Header Control,也就是说记录了本地表空间的Bitmap头控制信息,那么Oracle在修改数据文件的大小时,肯定要保护住这张表中的记录不被修改,这就是row cache lock产生的原因。

至于为什么对于普通的表被修改时,查询不会被阻塞,而这张表的查询却导致row cache lock,个人认为有两个原因,首先数据字典表的缓存和用户数据的缓存是不一样的,一个是ROW CACHE一个是DB_BUFFER,这是这里产生row cache lock的原因之一,更重要的一点是X$KTFBHC视图并不是真正Oracle数据库中的对象,而是Oracle内部程序实现的一个动态接口,虽然可以实现SQL的直接访问,但是显然与普通的Oracle对象不同,而不是数据库中的对象就意味着这个对象不具备原子性、事务性、一致性的特点,那么Oracle内部实现的时候很可能就是一个读写互斥的方式,因此产生row cache lock也是正常的。

 

 

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

下一篇: OLSNODES命令
请登录后发表评论 登录
全部评论
暂无介绍

注册时间:2007-12-29

  • 博文量
    1955
  • 访问量
    10441483