阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Oracle中的ROWID实现

208次阅读
没有评论

共计 3615 个字符,预计需要花费 10 分钟才能阅读完成。

一直以来,Oracle 的发展是如火如荼,依然非常成熟,无论是行业的人员和资料的丰富程度。对于数据库的体系结构的内容,下面这张图我估计很多 DBA 都快看吐了,每次一提起体系结构,总是会看到这张图。

Oracle 中的 ROWID 实现

而看着 10 年前的图,发现依旧能讲出不少的东西,很多技术的改变都是添砖加瓦,而动地基之类的改动,那就相当难了,从 12c 的体系结构可以看出,Oracle 真是下了血本了,根深蒂固的基础架构都要动,而且这个架构貌似以前还是在 SQL Server 已经有成形的使用。

我想说的是,技术的发展,我们都是其中的分子或者分母,如果说 ROWID 这个概念有什么可值得深挖的,估计想想都不大可能。一方面很多人可能因为一些特殊原因了解到它的存在,另一方面似乎它可用的空间就不是很大,而且如果想继续深究它的具体实现方式,这个就更难了。

先来说说 ROWID 的组成,如果说 ROWID 的格式如下:

OOOOOO.FFF.BBBBBB.RRR

那么 OOOOOO 就是 OBJECT_ID,可以通过 DBA_OBJECTS 查得。

FFF 是对应的数据文件号,可以通过 DBA_DATA_FILES 或者是 V$DATAFILE 查到

BBBBBB 是数据块号,这一点尤其值得说一说,数据字典层面,Oracle 对外开放的数据字典,最细粒度也就是 dba_extents 了,如果想看到更细节的数据块的信息,那也就只有 ROWID 可以看到了。

而 RRR 是对应的行数,也就是 row  number

ROWID 看起来如此强大,能够定位到如此细节的信息,那么 ROWID 我们有什么快捷的方式来查看和管理呢,我们能够像到的就是 DBMS_ROWID 了。

比如下面的语句,能够查到一些很详细的信息。

 select
  rowid as therowid, id,
  dbms_rowid.rowid_object(rowid) as objid,
  dbms_rowid.rowid_relative_fno(rowid) as relfilenum,
  dbms_rowid.ROWID_RELATIVE_FNO(rowid) as absfilenum,
  dbms_rowid.rowid_block_number(rowid) as blocknum,
  dbms_rowid.rowid_row_number(rowid) as rowslot
  from t where id in(1, 2, 500, 501)
 order by id; 
 THEROWID                  ID      OBJID RELFILENUM ABSFILENUM  BLOCKNUM    ROWSLOT
 —————— ———- ———- ———- ———- ———- ———-
 AAAVs+AABAAAXHJAAA          1      88894          1          1      94665          0
 AAAVs+AABAAAXHJAAB          2      88894          1          1      94665          1
 AAAVs+AABAAAXHJAHz        500      88894          1          1      94665        499
 AAAVs+AABAAAXHJAH0        501      88894          1          1      94665        500 但是可能你也有一种疑惑,这个 ROWID 看起来格式还真不简单,到底是咋实现的呢?DBMS_ROWID 是不会披露这些信息的,毫无疑问,这些内容是肯定被加密的。

我们有什么其他的办法来解读呢。首先一种说法是 ROWID 是根据 base64 来编码的。我们有没有办法来试一试,这一点还真找到了同样想法的技术友人,感兴趣可以参考这篇。

https://www.experts-exchange.com/articles/931/Decoding-the-Oracle-ROWID-and-some-Base64-for-fun.html

我们来简单测试一下。

首先是数据初始化,我们建立一个表,插入 10000 条数据,两个 SQL 轻松搞定。

create table t(id integer primary key,name varchar(1));
 insert into t select level,’A’ name from dual connect by level<=10000;   

我们查看几行数据。

SQL> select rowid from t where id<=2;
 ROWID
 ——————
 AAAVs+AABAAAXHJAAA
 AAAVs+AABAAAXHJAAB

末尾的 3 位是行数,那么我们解读一下它吧。

SQL> select substr(rowid, 16, 3)
                from t where id <= 2;
 SUBSTR(ROWID,16,3)
 ——————
 AAA
 AAB 这一点很显然就是如此,没有什么特别之处,而 base64 是要求至少 24 位,所以我们可以尝试再补充一位。

SQL> select LPAD(substr(rowid, 16, 3), 4, ‘A’)
                from t where id <= 2;
 LPAD(SUBSTR(ROWID,16,3),
 ————————
 AAAA
 AAAB

下面的这个步骤就很值得玩味了,那就是使用 base64 的方法来处理。

SQL> select utl_encode.base64_decode(utl_raw.cast_to_raw(lpad(substr(rowid, 16, 3), 4, ‘A’)))
                from t where id in(1, 2, 500, 501);
 ————————————
 000000
 000001
 0001F3
 0001F4 可以看出这个现实的结果是行数,但是实际上这个是十六进制的方式。沃恩需要再这个基础上进一步转换。

SQL> select to_number(utl_encode.base64_decode(utl_raw.cast_to_raw(lpad(substr(rowid, 16, 3), 4, ‘A’))), ‘XXXXXX’) as rowslot
          from t where id in(1, 2, 500, 501);
    ROWSLOT
 ———-
          0
          1
        499
        500

如此一来,整个过程是清晰了很多,那么这个说法到底是否靠谱呢。

我们可以使用它来得到和 dbms_rowid 同样的效果。

select rowid as therowid, id,
  to_number(utl_encode.base64_decode(utl_raw.cast_to_raw(lpad(substr(rowid,1, 6), 8, ‘A’))), ‘XXXXXXXXXXXX’) as objid,
  to_number(utl_encode.base64_decode(utl_raw.cast_to_raw(lpad(substr(rowid, 7, 3), 4, ‘A’))), ‘XXXXXX’) as filenum,
  to_number(utl_encode.base64_decode(utl_raw.cast_to_raw(lpad(substr(rowid, 10, 6), 8, ‘A’))), ‘XXXXXXXXXXXX’) as blocknum,
  to_number(utl_encode.base64_decode(utl_raw.cast_to_raw(lpad(substr(rowid, 16, 3), 4, ‘A’))), ‘XXXXXX’) as rowslot
  from t where id <= 2  ;   
 THEROWID                  ID      OBJID    FILENUM  BLOCKNUM    ROWSLOT
 —————— ———- ———- ———- ———- ———-
 AAAVs+AABAAAXHJAAA          1      88894          1      94665          0
 AAAVs+AABAAAXHJAAB          2      88894          1      94665 

所以说如此一来整个 ROWID 的实现方式就一目了然了,而在这个测试中如果结合 ROWNUM 其实也就更有意思了。我们后续来揉在一起来对比一下。

更多 Oracle 相关信息见 Oracle 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=12

本文永久更新链接地址 :http://www.linuxidc.com/Linux/2016-11/137672.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计3615字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中