我们通过学习知道,rowid 是存放行在磁盘上的具体位置,格式如下 AAAVU/AAHAAAACVAAA。
本章内容我们来揭秘下 rowid。
通过 rowid 去寻找数据是最快的,因为我都把物理位置告诉 oracle 了,oracle 只需要一次 IO 就能找到该数据。
那么 rowid 在块中是真实存储的吗?
显然不是,进程要读取哪个对象,哪个文件,哪个 BLOCK,哪一行时,这几个信息就动态拼接了 ROWID 并展现。所以没必要存储,浪费资源空间。
rowid 的组成
通过以下 SQL 我们把 rowid 显示为人能看懂的信息,那么我们能不能自己通过计算得出来呢,可以的,但我们要先了解下 rowid 的构成。
SELECT
DBMS_ROWID.ROWID_OBJECT('AAAVU/AAHAAAACVAAA') AS object_id,
DBMS_ROWID.ROWID_RELATIVE_FNO('AAAVU/AAHAAAACVAAA') AS file_id,
DBMS_ROWID.ROWID_BLOCK_NUMBER('AAAVU/AAHAAAACVAAA') AS block_number,
DBMS_ROWID.ROWID_ROW_NUMBER('AAAVU/AAHAAAACVAAA') AS row_number
FROM dual;
|OBJECT_ID|FILE_ID|BLOCK_NUMBER|ROW_NUMBER|
|---------|-------|------------|----------|
|87,359 |7 |149 |0 |
rowid 使用 base64 编码行的物理地址,编码字符包含 A-Z,a-z,0-9,+和 /。
rowid 由四部分组成,共 18 位代表 80 位二进制数,占用 10 个字节。
32bit obj# + 10bit file# + 22bit block# + 16bit row#
其中obj 用 6 位字符显示,file 用 3 位字符显示,block 用 6 位字符显示,row 用 3 位字符显示
所以,上诉例子可以分解为以下:
参考 base64 的编码规则,我们把 rowid 转换一下
AAAVU/ = A(0) + A(0) + A(0) + V(21) + U(20) + /(63)
AAH = A(0) + A(0) + H(7)
AAAACV = A(0) + A(0) + A(0) + A(0) + C(2) + V(21)
AAA = A(0) + A(0) + A(0)
得到转换后的 base64 后怎么计算呢。其实很简单。通过 从右到左 按 64 的幂次方计算就行了,
第 1 位(最右):×64⁰ ,第 2 位:×64¹ ,第 3 位:×64²以此类推。那我们代入公式自己计算一下对不对。
AAAVU/ = A(0) + A(0) + A(0) + V(21) + U(20) + /(63)=21*642+20*641+63*640 = 63 + 1280 + 86016 = 87359
AAH = A(0) + A(0) + H(7) = 7*640 =7
AAAACV = A(0) + A(0) + A(0) + A(0) + C(2) + V(21) =2*641+21*640 =128+21=149
AAA = A(0) + A(0) + A(0) = 0
跟我们用 SQL 得出的结果是一致的。
为什么一个数据文件最大是 32G,我们知道,数据文件 = 块个数 * 块大小。
那这个块个数是怎么得出来的。我们上面有说到,block 是占用22bit,也就
块编号的最大值 =
222−1=4,194,303222−1=4,194,303 或者 SELECT POWER(2, 22) max_block FROM dual;
数据文件的最大值
select 4194304*8/1024/1024 from dual;得出 32G
评论