关于ORACLE通过file_id与block_id定位数据库对象遇到的问题引发的思考

在ORACLE中,我们可以通过file_id(file#)与block_id(block#)去定位一个数据库对象(object)。例如,我们在10046生成的trace文件中file#=4 block#=266 blocks=8,那么我可以通过下面两个SQL去定位对象

SQL 1:此SQL效率较差,执行时间较长。

SELECT OWNER,
  SEGMENT_NAME,
  SEGMENT_TYPE,
  TABLESPACE_NAME
FROM DBA_EXTENTS
WHERE FILE_ID =&FILE_ID
  AND &BLOCK_ID BETWEEN BLOCK_ID AND BLOCK_ID + BLOCKS - 1;

SQL 2:此SQL效率较快(ORACLE 10g 中没有CACHEHINT字段)

SELECT OBJD,
  FILE#,
  BLOCK#,
  CLASS#,
  TS#,
  CACHEHINT,
  STATUS,
  DIRTY
FROM V$BH
WHERE FILE# = &FILE_ID
  AND BLOCK# = &BLOCK_ID;
SELECT OWNER, OBJECT_NAME FROM DBA_OBJECTS WHERE OBJECT_ID=&OBJECT_ID;

下面通过一个例子来演示一下,详情如下所示

SQL> COL OWNER FOR A12;
SQL> COL SEGMENT_NAME FOR A32;
SQL> SELECT OWNER  ,
 2   SEGMENT_NAME ,
 3   HEADER_FILE ,
 4   HEADER_BLOCK
 5 FROM DBA_SEGMENTS
 6 WHERE OWNER='TEST' AND SEGMENT_NAME='EMPLOYEE';
OWNER  SEGMENT_NAME      HEADER_FILE HEADER_BLOCK
------------ -------------------------------- ----------- ------------
TEST   EMPLOYEE         4   266
SQL>
SQL> SELECT OWNER,
 2   SEGMENT_NAME,
 3   SEGMENT_TYPE,
 4   TABLESPACE_NAME
 5 FROM DBA_EXTENTS
 6 WHERE FILE_ID = 4
 7   AND 266 BETWEEN BLOCK_ID AND BLOCK_ID + BLOCKS - 1;
OWNER  SEGMENT_NAME      SEGMENT_TYPE  TABLESPACE_NAME
------------ -------------------------------- ------------------ -----------------
TEST   EMPLOYEE       TABLE    USERS
SQL>
SQL> SELECT OBJD,
 2   FILE#,
 3   BLOCK#,
 4   CLASS#,
 5   TS#,
 6   CACHEHINT,
 7   STATUS,
 8   DIRTY
 9 FROM V$BH
 10 WHERE FILE# = 4
 11   AND BLOCK# = 266;
  OBJD  FILE#  BLOCK#  CLASS#  TS# CACHEHINT STATUS  D
---------- ---------- ---------- ---------- ---------- ---------- ---------- -
  76090   4  266   4   4   15 cr   N
  76090   4  266   4   4   15 cr   N
  76090   4  266   4   4   15 cr   N
SQL> SELECT OWNER, OBJECT_NAME FROM DBA_OBJECTS WHERE OBJECT_ID=76090;
OWNER  OBJECT_NAME
------------ ------------------------------------------------------------
TEST   EMPLOYEE
clip_image001

昨天在群里讨论一个关于空闲块的问题时,我验证测试时,发现一个奇怪的现象,使用下面SQL找到了一个最大空闲块。

SELECT UPPER(F.TABLESPACE_NAME)   AS "表空间名",
  D.TOT_GROOTTE_MB     AS "表空间大小(M)",
  D.TOT_GROOTTE_MB - F.TOTAL_BYTES AS "已使用空间(M)",
  TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99')
           AS "使用比",
  F.TOTAL_BYTES      AS "空闲空间(M)",
  F.MAX_BYTES      AS "最大空闲块(M)"
FROM
 (SELECT TABLESPACE_NAME,
 ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
 ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES
 FROM SYS.DBA_FREE_SPACE
 GROUP BY TABLESPACE_NAME
 ) F,
 (SELECT DD.TABLESPACE_NAME,
 ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB
 FROM SYS.DBA_DATA_FILES DD
 GROUP BY DD.TABLESPACE_NAME
 ) D
WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME;
SELECT FILE_ID,BLOCK_ID, BYTES,BLOCKS
FROM DBA_FREE_SPACE
WHERE TABLESPACE_NAME=&TABLESPACE_NAME
ORDER BY BYTES DESC;

然后我发现使用上面两个SQL查不到对应的对象。如下截图所示:

后面查了一下资料,发现在Oracle Database 10g引入了回收站功能后,会将回收站(RECYCLEBIN$)中的空间计算为自由空间,加入到dba_free_space字典中。在$ORACLE_HOME/rdbms/admin/catspace.sql中,你可以找到视图DBA_FREE_SPACE的定义,脚本如下:

ORACLE 10g中DBA_FREE_SPACE的定义:

create or replace view DBA_FREE_SPACE
 (TABLESPACE_NAME, FILE_ID, BLOCK_ID,
  BYTES, BLOCKS, RELATIVE_FNO)
as
select ts.name, fi.file#, f.block#,
  f.length * ts.blocksize, f.length, f.file#
from sys.ts$ ts, sys.fet$ f, sys.file$ fi
where ts.ts# = f.ts#
 and f.ts# = fi.ts#
 and f.file# = fi.relfile#
 and ts.bitmapped = 0
union all
select /*+ ordered use_nl(f) use_nl(fi) */
  ts.name, fi.file#, f.ktfbfebno,
  f.ktfbfeblks * ts.blocksize, f.ktfbfeblks, f.ktfbfefno
from sys.ts$ ts, sys.x$ktfbfe f, sys.file$ fi
where ts.ts# = f.ktfbfetsn
 and f.ktfbfetsn = fi.ts#
 and f.ktfbfefno = fi.relfile#
 and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
union all
select /*+ ordered use_nl(u) use_nl(fi) */
  ts.name, fi.file#, u.ktfbuebno,
  u.ktfbueblks * ts.blocksize, u.ktfbueblks, u.ktfbuefno
from sys.recyclebin$ rb, sys.ts$ ts, sys.x$ktfbue u, sys.file$ fi
where ts.ts# = rb.ts#
 and rb.ts# = fi.ts#
 and u.ktfbuefno = fi.relfile#
 and u.ktfbuesegtsn = rb.ts#
 and u.ktfbuesegfno = rb.file#
 and u.ktfbuesegbno = rb.block#
 and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
union all
select ts.name, fi.file#, u.block#,
  u.length * ts.blocksize, u.length, u.file#
from sys.ts$ ts, sys.uet$ u, sys.file$ fi, sys.recyclebin$ rb
where ts.ts# = u.ts#
 and u.ts# = fi.ts#
 and u.segfile# = fi.relfile#
 and u.ts# = rb.ts#
 and u.segfile# = rb.file#
 and u.segblock# = rb.block#
 and ts.bitmapped = 0
/
ORACLE 11g中DBA_FREE_SPACE的定义:
create or replace view DBA_FREE_SPACE
 (TABLESPACE_NAME, FILE_ID, BLOCK_ID,
  BYTES, BLOCKS, RELATIVE_FNO)
as
select ts.name, fi.file#, f.block#,
  f.length * ts.blocksize, f.length, f.file#
from sys.ts$ ts, sys.fet$ f, sys.file$ fi
where ts.ts# = f.ts#
 and f.ts# = fi.ts#
 and f.file# = fi.relfile#
 and ts.bitmapped = 0
union all
select /*+ ordered use_nl(f) use_nl(fi) */
  ts.name, fi.file#, f.ktfbfebno,
  f.ktfbfeblks * ts.blocksize, f.ktfbfeblks, f.ktfbfefno
from sys.ts$ ts, sys.x$ktfbfe f, sys.file$ fi
where ts.ts# = f.ktfbfetsn
 and f.ktfbfetsn = fi.ts#
 and f.ktfbfefno = fi.relfile#
 and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
union all
select /*+ ordered use_nl(u) use_nl(fi) */
  ts.name, fi.file#, u.ktfbuebno,
  u.ktfbueblks * ts.blocksize, u.ktfbueblks, u.ktfbuefno
from sys.recyclebin$ rb, sys.ts$ ts, sys.x$ktfbue u, sys.file$ fi
where ts.ts# = rb.ts#
 and rb.ts# = fi.ts#
 and u.ktfbuefno = fi.relfile#
 and u.ktfbuesegtsn = rb.ts#
 and u.ktfbuesegfno = rb.file#
 and u.ktfbuesegbno = rb.block#
 and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
union all
select ts.name, fi.file#, u.block#,
  u.length * ts.blocksize, u.length, u.file#
from sys.ts$ ts, sys.uet$ u, sys.file$ fi, sys.recyclebin$ rb
where ts.ts# = u.ts#
 and u.ts# = fi.ts#
 and u.segfile# = fi.relfile#
 and u.ts# = rb.ts#
 and u.segfile# = rb.file#
 and u.segblock# = rb.block#
 and ts.bitmapped = 0
/

那么在DBA_FREE_SPACE中找到的最大空闲块是否很有可能就是回收站中曾经的一个对象呢?那么我们来测试看看。

SQL> show parameter recyclebin;
NAME         TYPE  VALUE
------------------------------------ ----------- ------------------------------
recyclebin       string  on
SQL> CREATE TABLE ESCMOWNER.TTT
 2 AS
 3 SELECT * FROM DBA_OBJECTS;
Table created.
SQL> COL OWNER FOR A12;
SQL> COL SEGMENT_NAME FOR A32;
SQL> SELECT OWNER,SEGMENT_NAME, HEADER_FILE, HEADER_BLOCK
 2 FROM DBA_SEGMENTS
 3 WHERE OWNER='ESCMOWNER' AND SEGMENT_NAME='TTT' ;
OWNER  SEGMENT_NAME      HEADER_FILE HEADER_BLOCK
------------ -------------------------------- ----------- ------------
ESCMOWNER TTT          97  113025
SQL>
SQL> SELECT * FROM X$KTFBFE WHERE KTFBFEFNO=97;
ADDR     INDX INST_ID KTFBFETSN KTFBFEFNO KTFBFEBNO KTFBFEBLKS
---------------- ---------- ---------- ---------- ---------- ---------- ----------
00007F57B2388CA0  222   1   9   97  524169  120
SQL> DROP TABLE ESCMOWNER.TTT;
Table dropped.
SQL> COL ORIGINAL_NAME FOR A16;
SQL> SELECT OBJ#,OWNER#,ORIGINAL_NAME,FILE#,BLOCK# ,FLAGS,SPACE FROM RECYCLEBIN$;
  OBJ#  OWNER# ORIGINAL_NAME   FILE#  BLOCK#  FLAGS  SPACE
---------- ---------- ---------------- ---------- ---------- ---------- ----------
 805429   73 TTT      97  113025   30  896
SQL> PURGE DBA_RECYCLEBIN;
DBA Recyclebin purged.
SQL> SELECT * FROM X$KTFBFE WHERE KTFBFEFNO=97 ;
ADDR     INDX INST_ID KTFBFETSN KTFBFEFNO KTFBFEBNO KTFBFEBLKS
---------------- ---------- ---------- ---------- ---------- ---------- ----------
00007F57B2388CA0  222   1   9   97  113025   8
00007F57B2388CA0  225   1   9   97  524169  120
SQL>
clip_image003

如上所示,清空回收站对象后,你会发现X$KTFBFE中多了一条记录,KTFBFEFNO 和 KTFBFEBNO分别为97 ,113025, 这个值显然就是删除对象TTT曾经的FILE_ID(97)和BLOCK_ID(113025)值。

另外,在测试过程中发现,并不是每次的测试结果都是在X$KTFBFE中多一条记录,有时候记录不会变化,但是X$KTFBFE中某条记录的KTFBFEBNO会变化,而这个变化跟清空回收站是有关系的。如下案例所示:

SQL> show parameter recyclebin;
NAME         TYPE  VALUE
------------------------------------ ----------- ------------------------------
recyclebin       string  on
SQL> CREATE TABLE TEST.TTT
 2 AS
 3 SELECT * FROM DBA_OBJECTS;
Table created.
SQL> COL OWNER FOR A12;
SQL> COL SEGMENT_NAME FOR A32;
SQL> SELECT OWNER,SEGMENT_NAME, HEADER_FILE, HEADER_BLOCK
 2 FROM DBA_SEGMENTS
 3 WHERE OWNER='TEST' AND SEGMENT_NAME='TTT' ;
OWNER  SEGMENT_NAME      HEADER_FILE HEADER_BLOCK
------------ -------------------------------- ----------- ------------
TEST   TTT          5   130
SQL> SELECT * FROM X$KTFBFE WHERE KTFBFEFNO=5 ;
ADDR     INDX INST_ID KTFBFETSN KTFBFEFNO KTFBFEBNO KTFBFEBLKS
---------------- ---------- ---------- ---------- ---------- ---------- ----------
00002BA829B19558  150   1   6   5  1280  506752
00002BA829B19558  151   1   6   5  508032  16256
SQL> DROP TABLE TEST.TTT;
Table dropped.
SQL>
SQL> COL ORIGINAL_NAME FOR A16;
SQL> SELECT OBJ#,OWNER#,ORIGINAL_NAME,FILE#,BLOCK# ,FLAGS,SPACE FROM RECYCLEBIN$;
  OBJ#  OWNER# ORIGINAL_NAME   FILE#  BLOCK#  FLAGS  SPACE
---------- ---------- ---------------- ---------- ---------- ---------- ----------
  82820   85 TTT      5  130   30  1152
SQL> SELECT * FROM X$KTFBFE WHERE KTFBFEFNO=5 ;
ADDR     INDX INST_ID KTFBFETSN KTFBFEFNO KTFBFEBNO KTFBFEBLKS
---------------- ---------- ---------- ---------- ---------- ---------- ----------
00002BA829B159D8  150   1   6   5  1280  506752
00002BA829B159D8  151   1   6   5  508032  16256
SQL> PURGE DBA_RECYCLEBIN;
DBA Recyclebin purged.
SQL> SELECT * FROM X$KTFBFE WHERE KTFBFEFNO=5 ;
ADDR     INDX INST_ID KTFBFETSN KTFBFEFNO KTFBFEBNO KTFBFEBLKS
---------------- ---------- ---------- ---------- ---------- ---------- ----------
00002BA829B159D8  150   1   6   5  128  507904
00002BA829B159D8  151   1   6   5  508032  16256
SQL>
clip_image004

如上所示,在清空回收站的表以后,你查询X$KTFBFE,就会发现其中一条记录的KTFBFEBNO的变化了,它们的关系为

1280 -1152 = 128

所以,你会看到KTFBFEBNO的值从1280变为了128了。此时你查看DBA_FREE_SPACE,就会看到这样的情况。所以当清空回收站时,有可能是数据库将这个表的空间标记为了空闲块,也有可能是将这个空闲块合并到其它空闲块去了。

X$KTFBFE其实是这几个单词[k]ernel [t]ablespace [f]ile [b]itmapped [f]ree [e]xtents 的首字母。关于这个系统视图最深入的介绍,莫过于这篇文章谈谈Oracle dba_free_space,有兴趣可以验证、测试一下。

以上所述是小编给大家介绍的关于ORACLE通过file_id与block_id定位数据库对象遇到的问题引发的思考,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

(0)

相关推荐

  • 解析Oracle数据库中的对象集合schema

    搭建一个oracle,下面会有很多schema,每个schema下的数据都不影响. 感觉和mysql的库的概念很像,现在用的数据库管理系统其实也是这么划分的,mysql用的ip+port+库标识,oracle用ip+port+schema标识,平时还总听到一个实例的概念,我的理解就是实例就是一系列相关进程,代表了一个数据库服务.目前线上为了节省资源,常常把机器分成多个实例,用不同的端口号标识,每个实例上有多个schema. 旭哥跟我说的很形象,oracle一个实例上有对应多个库.mysql一个库

  • 关于ORACLE通过file_id与block_id定位数据库对象遇到的问题引发的思考

    在ORACLE中,我们可以通过file_id(file#)与block_id(block#)去定位一个数据库对象(object).例如,我们在10046生成的trace文件中file#=4 block#=266 blocks=8,那么我可以通过下面两个SQL去定位对象 SQL 1:此SQL效率较差,执行时间较长. SELECT OWNER, SEGMENT_NAME, SEGMENT_TYPE, TABLESPACE_NAME FROM DBA_EXTENTS WHERE FILE_ID =&F

  • Oracle 12c 新特性之多线程数据库操作

    之前我们学习Oracle基础的时候,有一个概念,叫多进程和多线程.在Unix/Linux等环境下面.数据库是以多进程的方式运行的,当一个会话连接进来,就会通过监听,然后在服务器上创建一个进程.而在Windows上面它是以多线程的方式来运行的.一个进程有很多个thread线程.而在12c这个版本上面,Oracle在Unix/Linux平台上做出了一些改变,引入了多线程的方式.通过参数threaded_execution,我们可以控制数据库是以多进程方式运行还是以多线程方式运行,默认该参数是fals

  • ORACLE正则匹配查询LIKE查询多个值检索数据库对象

    字符串’^198[0-9]$’可以匹配‘1980-1989’,如果希望统计出公司那些员工是80年-89年入职的,就可以使用如下的SQL语句: select * from emp e where regexp_like(to_char( e.hiredate,'yyyy'),'^198[0-9]$'); 正则表达式中常用到的元数据(metacharacter)如下: ^ 匹配字符串的开头位置. $ 匹配支付传的结尾位置. * 匹配该字符前面的一个字符0次,1次或者多次出现.例如52*oracle

  • Oracle数据库对象的使用详解

    目录 一.序列 二.同义词的作用 三.视图的定义及使用 四.索引的定义及使用 五.总结 一.序列 序列可以使用在数据库表的自动增长列中来用,假如我们的学生表的id想从1开始,然后自动增长,每次增加2,也就是学生id是1.3.5.7.9这种的,我们就可以配合序列来使用序列有以下属性sequence_name:序列名称min_value:当前序列的最小值max_value:当前序列的最大值increment_by:每次序列增长的步长cy:是否为循环序列or:是否需要排序cache_size:缓存个数

  • Mysql通过explain分析定位数据库性能问题

    目录 引言 explain基础 exlpain分析实战 总结 引言 数据库性能优化是每个后端程序猿必备的基础技能之一,而Mysql中的explain堪称Mysql的性能优化分析神器,我们可以通过它来分析SQL语句的对应的执行计划在Mysql底层到底是如何执行的,它对于我们评估SQL的执行效率以及确定Mysql的性能优化方向具有重要的意义.但是很多同学对于如何根据explain对已有SQL进行深度的执行分析还是丈二和尚摸不着头脑,因此本文详细阐述通过explain分析定位数据库性能问题. expl

  • 详解PostgreSql数据库对象信息及应用

    PostgreSql数据库对象主要有数据库.表.视图.索引.schema.函数.触发器等.PostgreSql提供了information_schema schema,其中包括返回数据库对象的视图.如用户有访问权限,可以也在pg_catalog schema中查询表.视图等对象. 1. 查询数据库对象 下面通过示例分别展示如何查询各种数据库对象. 1.1 表查询 PostgreSql 表信息可以从information_schema.tables 或 pg_catalog.pg_tables 视

  • oracle 12c创建可插拔数据库(PDB)与用户详解

    前言 由于oracle 12c使用了CDB-PDB架构,类似于docker,在container-db内可以加载多个pluggable-db,因此安装后需要额外配置才能使用. 一.修改listener.ora , tnsnames.ora ###listener.ora### LISTENER = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) (CONNECT_DATA = (SERVICE_

  • 深入浅析Oracle数据库管理之创建和删除数据库

    Oracle数据库的数据文件(扩展名为DBF的文件)是用于保存数据库中数据的文件,系统数据.数据字典数据.临时数据.索引数据.应用数据等都物理地存储在数据文件中.用户对数据库中数据的操作,例如数据的插入.删除.修改和查询等,其本质都是对数据文件进行操作.所有数据文件占据空间的大小决定了数据库容量的大小. 一.数据库管理概述 在完成Oracle软件安装后,DBA就应该对组织和管理数据库负责任,其主要任务是: (1)启动和关闭数据库: (2)创建数据库: (3)删除数据库: (4)调整初始化参数:

  • Oracle 12C实现跨网络传输数据库详解

    前言 跨网络传输数据库,可以通过使用network_link参数来执行导入操作,导入操作将使用数据库链路,不需要生成dump文件. 操作步骤如下: 1.在目标数据库中创建链接到源数据库的数据链路.执行导入操作的用户必须要有datapump_imp_full_database权限,并且连接到源数据库的数据链路也必须连接到一个有datapump_exp_full_database角色的用户.在源数据库中用户不能有sysdba管理权限. 2.在源数据库上将所有用户表空间置为只读模式 3.将源数据库中所

  • ORACLE 常用的SQL语法和数据对象

    1.INSERT (往数据表里插入记录的语句) INSERT INTO 表名(字段名1, 字段名2, --) VALUES ( 值1, 值2, --); INSERT INTO 表名(字段名1, 字段名2, --) SELECT (字段名1, 字段名2, --) FROM 另外的表名; 字符串类型的字段值必须用单引号括起来, 例如: 'GOOD DAY' 如果字段值里包含单引号' 需要进行字符串转换, 我们把它替换成两个单引号''. 字符串类型的字段值超过定义的长度会出错, 最好在插入前进行长度

随机推荐