rowid就像是记录的详细地址,想要寻找记录就需要通过这个详细地址去寻找。
rowid存储在索引中而不是在表中。
我们可以通过以下包通过rowid找到文件号,块号,行号。
dbms_rowid.rowid_relative_fno -- 文件号
dbms_rowid.rowid_block_number --块号
dbms_rowid.rowid_row_number --行号
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
PL/SQL Release 12.2.0.1.0 - Production
CORE 12.2.0.1.0 Production
TNS for Linux: Version 12.2.0.1.0 - Production
NLSRTL Version 12.2.0.1.0 - Production
SQL> select rowid,dbms_rowid.rowid_relative_fno(rowid) fno,dbms_rowid.rowid_block_number(rowid) bno from liu.test;
ROWID FNO BNO
------------------ ---------- ----------
AAAR3sAAMAAAACGAAA 12 134
liu.test表插入了一行测试数据,我们先找到该行记录的rowid,fno(relative file id),bno(block id)
rowid由对象号,数据文件号,块号,行号构成。
然后我们通过base64表将rowid分解转化成十进制
1-6位,对象号:AAAR3s-->0 0 0 1755 44 -->0*64^5+0*64^4+0*64^3+17*64^2+55*64^1+44*64^0=73196
7-9位,数据文件号:AAM-->0 0 12 -->0*64^2+0*64^1+12*64^0=12 (对应fno)
10-15位,块号:AAAACG-->00 0 2 6-->0*64^5+0*64^4+0*64^3+0*64^2+2*64^1+6*64^0=134 (对应bno)
16-18位,行号:AAA--> 0 0 0--> ...=0
base64转换表:
索引 | 对应字符 | 索引 | 对应字符 | 索引 | 对应字符 | 索引 | 对应字符 |
0 | A | 17 | R | 34 | i | 51 | z |
1 | B | 18 | S | 35 | j | 52 | 0 |
2 | C | 19 | T | 36 | k | 53 | 1 |
3 | D | 20 | U | 37 | l | 54 | 2 |
4 | E | 21 | V | 38 | m | 55 | 3 |
5 | F | 22 | W | 39 | n | 56 | 4 |
6 | G | 23 | X | 40 | o | 57 | 5 |
7 | H | 24 | Y | 41 | p | 58 | 6 |
8 | I | 25 | Z | 42 | q | 59 | 7 |
9 | J | 26 | a | 43 | r | 60 | 8 |
10 | K | 27 | b | 44 | s | 61 | 9 |
11 | L | 28 | c | 45 | t | 62 | + |
12 | M | 29 | d | 46 | u | 63 | / |
13 | N | 30 | e | 47 | v | ||
14 | O | 31 | f | 48 | w | ||
15 | P | 32 | g | 49 | x | ||
16 | Q | 33 | h | 50 | y |
现在数据文件号,块号都对应了,我们来查找对象号
SQL> select owner,object_name,object_id from dba_objects where object_name = 'TEST';
OWNER OBJECT_NAME OBJECT_ID
---------- ------------------------------ ----------
LIU TEST 73196
对象号也对应了
行号为0,是否每一行+1,从0开始呢。我们再插入数据进行验证
循环插入50w行数据
begin
for i in 1..500000
loop
insert into liu.test values(i);
end loop;
commit;
end;
/
SQL> select count(1) from liu.test;
COUNT(1)
----------
500001
SQL> select * from (select rowid from liu.test order by a asc) where rownum<=5;
ROWID
------------------
AAAR3sAAMAAAACGAAA
AAAR3sAAMAAAACGAAB
AAAR3sAAMAAAACGAAC
AAAR3sAAMAAAACGAAD
AAAR3sAAMAAAACGAAE
可以看出,当行号是持续递增的,0表示第一行,1表示第二行以此类推
但是这里会有一个问题,行号有最大值--///,也就是说每个块只能存储AAA--///的数据,也就是0--63*64^2+63*64^1+63*64^0,也就是64^3=262144行。
但是oracle并没有使用所有的basic64编码号
select a,rowid from liu.test where rowid like 'AAAR3sAAMAAAACG___' order by rowid asc;
...
A ROWID
---------- ------------------
649 AAAR3sAAMAAAACGAKJ
650 AAAR3sAAMAAAACGAKK
651 AAAR3sAAMAAAACGAKL
652 AAAR3sAAMAAAACGAKM
653 AAAR3sAAMAAAACGAKN
654 AAAR3sAAMAAAACGAKO
655 AAAR3sAAMAAAACGAKP
656 AAAR3sAAMAAAACGAKQ
657 AAAR3sAAMAAAACGAKR
658 AAAR3sAAMAAAACGAKS
659 AAAR3sAAMAAAACGAKT
660 rows selected.
select a,rowid from liu.test where rowid like 'AAAR3sAAMAAAACH___' order by rowid asc;
...
A ROWID
---------- ------------------
1309 AAAR3sAAMAAAACHAKJ
1310 AAAR3sAAMAAAACHAKK
1311 AAAR3sAAMAAAACHAKL
1312 AAAR3sAAMAAAACHAKM
1313 AAAR3sAAMAAAACHAKN
1314 AAAR3sAAMAAAACHAKO
1315 AAAR3sAAMAAAACHAKP
1316 AAAR3sAAMAAAACHAKQ
1317 AAAR3sAAMAAAACHAKR
1318 AAAR3sAAMAAAACHAKS
1319 AAAR3sAAMAAAACHAKT
660 rows selected.
事实并非我们想象的那样,每个块最多存放660行数据。这也是有道理的,因为oracle块的大小是固定的,比如8k,那么他的行数不可能非常的高。
那么再看看660行发生了什么
SQL> select t1.rid from (select rowid rid,rownum rn from liu.test order by a asc)t1 where t1.rn>=658 and t1.rn<=662;
RID
------------------
AAAR3sAAMAAAACDAKR
AAAR3sAAMAAAACDAKS
AAAR3sAAMAAAACDAKT
AAAR3sAAMAAAACEAAA
AAAR3sAAMAAAACEAAB
当行到AKT时,块号+1,行号从0开始计算。
总结:
1.rowid记录了行记录的物理存放位置,通过basic64编码或者dbms_rowid转换转换rowid找到那个位置
2.每个块最多存放660行记录,当插入数据时要超过阈值(pct_free)的时候便把数据插入到下一个块
#################分割线20190328###############
rowid自增请再阅读我关于rowid的文章https://blog.csdn.net/qq_40687433/article/details/88868112
对于rowid的理解会更上一层楼