Oracle中的ROWID实现(r10笔记第95天)
一直以来,Oracle的发展是如火如荼,依然非常成熟,无论是行业的人员和资料的丰富程度。对于数据库的体系结构的内容,下面这张图我估计很多DBA都快看吐了,每次一提起体系结构,总是会看到这张图。
而看着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其实也就更有意思了。我们后续来揉在一起来对比一下。
- ambari安装指南
- Spring实战——通过Java代码装配bean
- WCF技术剖析之三十一: WCF事务编程[中篇]
- Spring实战——无需一行xml配置实现自动化注入
- 基于改进人工蜂群算法的K均值聚类算法(附MATLAB版源代码)
- RabbitMQ入门-Routing直连模式
- WCF技术剖析之三十二:一步步创建一个完整的分布式事务应用
- .NET的资源并不限于.resx文件,你可以采用任意存储形式[上篇]
- RabbitMQ入门-消息订阅模式
- 年终盘点:2018最值得学习的几种热门编程语言
- 如何编写没有Try/Catch的程序
- RabbitMQ入门-消息派发那些事儿
- RabbitMQ入门-高效的Work模式
- 谈谈分布式事务之四: 两种事务处理协议OleTx与WS-AT
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- HW|蓝队实战溯源反制手册分享
- 工具开发|Burp插件Unexpected_information
- 爱了!安利一个相见恨晚的可视化学习网站
- pandas+PyQt5轻松制作数据处理工具
- Python高效编程之88条军规(1):编码规范、字节序列与字符串
- 这是一份 pip 常用命令小结~
- 太震撼了,我用python画出全北京的公交线路动图
- 小伙Python爬虫并自制新闻网站,太好玩了
- TRTC Android端开发接入学习之视频会议(八)
- MySQL锁都分不清,怎么面试进大厂?
- Kubernetes Controller高可用诡异的15mins超时
- 这几项超好用的云开发扩展能力,别说你还不知道!
- Ubuntu上一键卸载安装mysql脚本
- Python-批量修改图片全部颜色,批量修改图片的指定颜色,马甲包一键换主题UI
- 【SpringBoot DB 系列】h2databse 集成示例 demo