ROWID

1.认识ROWID

 

SQL> select rowid from dept where rownum < 2;

 

ROWID各列信息格式如下:

 

数据对象编号文件编号 块编号 行编号

OOOOOO             FFF            BBBBBB RRR

 

简单查看ROWID信息

select rowid ,

substr(rowid,1,6) "OBJECT",

substr(rowid,7,3) "FILE",

substr(rowid,10,6) "BLOCK",

substr(rowid,16,3) "ROW"

from dept

/

 

ROWNUM是oracle系统顺序分配为从查询返回的行的编号。

返回的第一行分配的是1,第二行是2,依此类推。

这个伪字段可以用于限制查询返回的总行数,且rownum不能以任何表的名称作为前缀。

 

 

ROWID分两种:扩展ROWID和受限制的ROWID,后者为8I时的ROWID,现在已经废弃。ROWID格式如下:

 ROWID_第1张图片

execute dbms_stats.gather_table_stats('TEST','TT1'); //分析表

 

SET UNUSED COLUMN会对一列进行重命名,可以在下面数据字典中看到


ROWID_第2张图片

 

SQL> alter table DBA_SEGMENTS DROP unused columns; // 在这里释放空间

再次查询


ROWID_第3张图片

 

rowid

 

 

其实表里的每一条数据都隐藏着一个非常重要的东西——rowid

 

rowid叫伪列,它并不是我们在创建表的时候所指定的具体的某一列。而是ORACLE数据库自动为每行数据所附加的一列。

 

比如表里面有完全相同的两行数据,我们要删除其中一行,你总得找出两行不一样的地方,ROWID就是一种选择。如下:

 

SQL> select A.ROWID,A.* from tt A;

 

ROWID                     ID NAME

------------------ ---------- ----------

AAANMfAAEAAAE0eAAA         1 a

AAANMfAAEAAAE0eAAB         1 a

 

SQL>

 

oracle可以根据ROWID准确地找到这行数据所存放的具体的物理位置。

 

ROWID的格式

 

SQL> select rowid ,

 2 substr(rowid,1,6) "OBJECT",

 3 substr(rowid,7,3) "FILE",

 4 substr(rowid,10,6) "BLOCK",

 5 substr(rowid,16,3) "ROW"

 6 from dept

 7 /

 

ROWID             OBJECT                  FILE        BLOCK                   ROW

------------------ ------------------------ ------------ ------------------------ ------------

AAAMfNAAEAAAAAQAAA AAAMfN                  AAE         AAAAAQ                  AAA

AAAMfNAAEAAAAAQAAB AAAMfN                  AAE         AAAAAQ                  AAB

AAAMfNAAEAAAAAQAAC AAAMfN                  AAE         AAAAAQ                  AAC

AAAMfNAAEAAAAAQAAD AAAMfN                  AAE         AAAAAQ                  AAD

 

SQL>

 

2.数据对象编号

 

有两个对象编号:OBJECT_ID 和 DATA_OBJECT_ID,前者是指对象编号,后者是数据对象编号,也就是段编号,也就是ROWID的前6个字符标识。

 

对象和段是两个概念,是对象不一定是段,是段肯定就是对象。

 

SQL> select OBJECT_NAME,OBJECT_ID,DATA_OBJECT_ID from dba_objects where object_name='TT';

 

OBJECT_NAME                                        OBJECT_ID DATA_OBJECT_ID

-------------------------------------------------- ---------- --------------

TT                                                     54047         54047

 

SQL>

 

 

比如你在数据库中建立了一个存储过程,它在数据库中就是一个对象。表、视图、函数、存储过程在数据库中都叫对象。

 

 

我们经常提到的段其实就是表和索引。ORACLE里有数据段,索引段,临时段和回滚段。我们介绍的和数据有关的段一种是表一种是索引。当然表还有索引组织表,分区表,临时表等其他类型的表。

 

OBJECT_ID 和 DATA_OBJECT_ID 有什么区别呢?

 

这两个编号在刚刚创建的时候都是一样的。

 

OBJECT_ID:对象编号。凡是对象,数据库都会给它分配一个对象编号,对象一旦建立,对象编号就不会再次发生改变。即使对象名称变了,对象编号也不变。如下:

 

SQL> conn scott/tiger;

 

SQL> alter table tt rename to tt1;

 

SQL> conn / as sysdba

 

SQL> select OBJECT_NAME,OBJECT_ID,DATA_OBJECT_ID from dba_objects where object_name='TT1';

 

OBJECT_NAME                                        OBJECT_ID DATA_OBJECT_ID

-------------------------------------------------- ---------- --------------

TT1                                                    54047         54047

 

SQL>

 

 

DATA_OBJECT_ID:数据段ID,其实就是段的ID,段是数据库逻辑结构的内容,它描述的是ORACLE物理空间的使用。只要它的存放位置发生了改变,DATA_OBJECT_ID 就会发生改变。如下:

 

表在没有迁移到另一表空间的ROWID如下:

 

SQL> select A.*,rowid from tt1 A;

 

       ID NAME      ROWID

---------- ---------- ------------------

        1 a         AAANMfAAEAAAE0eAAA

        1 a         AAANMfAAEAAAE0eAAB

 

SQL>

 

 

SQL> alter table scott.tt1 move tablespace example;

 

Table altered.

 

SQL> conn scott/tiger;

Connected.

SQL> select A.*,rowid from tt1 A;

 

       ID NAME      ROWID

---------- ---------- ------------------

        1 a         AAANMgAAFAAAAP0AAA

        1 a         AAANMgAAFAAAAP0AAB

 

SQL> conn / as sysdba

 

SQL> select OBJECT_NAME,OBJECT_ID,DATA_OBJECT_ID from dba_objects where object_name='TT1';

 

OBJECT_NAME                                        OBJECT_ID DATA_OBJECT_ID

-------------------------------------------------- ---------- --------------

TT1                                                    54047         54048

 

SQL>

 

哪些操作可以使DATA_OBJECT_ID发生变化呢?其实TRUNCATE也能使DATA_OBJECT_ID发生变化。如下:

 

SQL> select OBJECT_NAME,OBJECT_ID,DATA_OBJECT_ID from dba_objects where object_name='TT1';

 

OBJECT_NAME                                        OBJECT_ID DATA_OBJECT_ID

-------------------------------------------------- ---------- --------------

TT1                                                    54047         54048

 

SQL> truncate table scott.tt1;

 

Table truncated.

 

SQL> select OBJECT_NAME,OBJECT_ID,DATA_OBJECT_ID from dba_objects where object_name='TT1';

 

OBJECT_NAME                                        OBJECT_ID DATA_OBJECT_ID

-------------------------------------------------- ---------- --------------

TT1                                                    54047         54049

 

SQL>

 

 

TRUNCATE 是一个DDL命令,所以TRUNCATE一张表所花的时间和表里数据的多与少无关。

 

TRUNCATE的原理:是DDL命令,凡是DDL命令,不涉及修改数据,只涉及修改元数据。元数据存放在数据字典中,用于描述对象的结构,对象的创建语法就是元数据。TRUNCATE表只修改SYSTEM 表空间对该表的描述,

 

TRUNCATE一张表会将该表重命名并重新建立一个对象。所以它的速度很快。

 

删除一列:要释放这列所占用的空间并修改元数据。如果列的数据大,DROP 一列可能花的时间很长,可能列上还有锁,所以删除一列风险很大

 

SYS用户下的列不支持删除操作,如下所示:

 

SQL> conn / as sysdba

Connected.

SQL> create table t1 (id int,name varchar2(10));

 

Table created.

 

SQL> alter table t1 drop column id;

alter table t1 drop column id

*

ERROR at line 1:

ORA-12988: cannot drop column from table owned by SYS

 

 

SQL>

 

SQL> alter table dba_segments drop column SEGMENT_NAME; // 删除列后数据再也无法找回

 

Table altered.

 

SQL>

 

SQL> exec dbms_stats.gather_table_stats('SCOTT','DBA_SEGMENTS');

 

PL/SQL procedure successfully completed.

 

SQL> select BLOCKS,EMPTY_BLOCKS from user_tables where table_name='DBA_SEGMENTS';

 

   BLOCKS EMPTY_BLOCKS

---------- ------------

       73           7

 

SQL>

 

直接使某一列无效

SQL> alter table DBA_SEGMENTS set unused column HEADER_BLOCK;  // 不释放空间,会重命名列。删除列后数据再也无法找回,它不释放空间,在数据库繁忙的时候可用此方法

 

Table altered.

 

SQL>

 

SQL> select OWNER,TABLE_NAME,COLUMN_NAME,DATA_TYPE from dba_tab_cols where table_name='DBA_SEGMENTS';

 

OWNER     TABLE_NAME          COLUMN_NAME                   DATA_TYPE

---------- -------------------- ------------------------------ --------------------

SCOTT     DBA_SEGMENTS        OWNER                         VARCHAR2

SCOTT     DBA_SEGMENTS        SEGMENT_TYPE                  VARCHAR2

SCOTT     DBA_SEGMENTS        HEADER_FILE                   NUMBER

SCOTT     DBA_SEGMENTS        BYTES                         NUMBER

SCOTT     DBA_SEGMENTS        BLOCKS                        NUMBER

SCOTT     DBA_SEGMENTS        EXTENTS                       NUMBER

SCOTT     DBA_SEGMENTS        INITIAL_EXTENT                NUMBER

SCOTT     DBA_SEGMENTS        NEXT_EXTENT                   NUMBER

SCOTT     DBA_SEGMENTS        MIN_EXTENTS                   NUMBER

SCOTT     DBA_SEGMENTS        MAX_EXTENTS                   NUMBER

SCOTT     DBA_SEGMENTS        PCT_INCREASE                  NUMBER

 

OWNER     TABLE_NAME          COLUMN_NAME                   DATA_TYPE

---------- -------------------- ------------------------------ --------------------

SCOTT     DBA_SEGMENTS        FREELISTS                     NUMBER

SCOTT     DBA_SEGMENTS        FREELIST_GROUPS               NUMBER

SCOTT     DBA_SEGMENTS        RELATIVE_FNO                  NUMBER

SCOTT     DBA_SEGMENTS        BUFFER_POOL                   VARCHAR2

SYS       DBA_SEGMENTS        INITIAL_EXTENT                NUMBER

SYS       DBA_SEGMENTS        NEXT_EXTENT                   NUMBER

SYS       DBA_SEGMENTS        PCT_INCREASE                  NUMBER

SYS       DBA_SEGMENTS        BUFFER_POOL                   VARCHAR2

SYS       DBA_SEGMENTS        OWNER                         VARCHAR2

SYS       DBA_SEGMENTS        BLOCKS                        NUMBER

SYS       DBA_SEGMENTS        HEADER_FILE                   NUMBER

 

OWNER     TABLE_NAME          COLUMN_NAME                   DATA_TYPE

---------- -------------------- ------------------------------ --------------------

SYS       DBA_SEGMENTS        MAX_EXTENTS                   NUMBER

SCOTT     DBA_SEGMENTS        SYS_C00004_12082923:33:29$    NUMBER

SYS       DBA_SEGMENTS        RELATIVE_FNO                  NUMBER

SYS       DBA_SEGMENTS        TABLESPACE_NAME               VARCHAR2

SYS       DBA_SEGMENTS        FREELIST_GROUPS               NUMBER

SYS       DBA_SEGMENTS        EXTENTS                       NUMBER

SYS       DBA_SEGMENTS        PARTITION_NAME                VARCHAR2

SYS       DBA_SEGMENTS        BYTES                         NUMBER

SYS       DBA_SEGMENTS        HEADER_BLOCK                  NUMBER

SYS       DBA_SEGMENTS        FREELISTS                     NUMBER

SYS       DBA_SEGMENTS        SEGMENT_NAME                  VARCHAR2

 

OWNER     TABLE_NAME          COLUMN_NAME                   DATA_TYPE

---------- -------------------- ------------------------------ --------------------

SYS       DBA_SEGMENTS        MIN_EXTENTS                   NUMBER

SYS       DBA_SEGMENTS        SEGMENT_TYPE                  VARCHAR2

 

35 rows selected.

 

SQL>

 

 

SQL> alter table DBA_SEGMENTS DROP unused columns; // 在这里释放空间

 

 

3.表空间脱机不能访问表里的数据却能删除表

 

表空间脱机后,里面的数据不能访问,但里面的对象却可以删除,因为删除对象是DDL命令,DDL命令只涉及修改元数据,而元数据在SYSTEM表空间里,真正的数据才存放在USERS表空间里。

 

SQL> alter tablespace users offline;

 

Tablespace altered.

 

SQL> select * from scott.emp;

select * from scott.emp

                    *

ERROR at line 1:

ORA-00376: file 4 cannot be read at this time

ORA-01110: data file 4: '/u01/app/oracle/oradata/caland/users01.dbf'

 

 

SQL> drop table scott.emp;

 

Table dropped.

 

SQL>

 

SQL> flashback table emp to before drop;

flashback table emp to before drop

*

ERROR at line 1:

ORA-38305: object not in RECYCLE BIN

 

SQL> conn scott/tiger;

Connected.

SQL> flashback table emp to before drop;

 

Flashback complete.

 

SQL>

 

4.相对文件编号

数据文件编号有相对文件编号和绝对文件编号

SQL> conn / as sysdba

Connected.

SQL> select file_id,relative_fno from dba_data_files;

 

  FILE_ID RELATIVE_FNO

---------- ------------

        4           4

        3           3

        2           2

        1           1

        5           5

        7           7

        6           6

        8           8

 

8 rows selected.

 

SQL>

针对8K的数据文件,每个数据库有65535个数据文件,每个表空间最多有1023个数据文件。当一个数据库里的数据文件数小于等于1023的时候,相对文件编号和绝对文件编号相同。

 

绝对文件编号是针对整个数据库而言的,相对文件编号是相对某个表空间而言的,但为什么相对文件编号和绝对文件编号还会相同呢?有待研究。

 

5.ROWID的编码格式

 

ROWID是一个由64进制的组成的长度为16的字符串。

AAANMf  AAE  AAAE0e  AAA 6+3+6+3=16个字符)

A~Z表示025

a~z表示2651

09表示5261

+表示62

/表示63

 

AAANMF=13*64*64+12*64+5

53248+768 +5

 ROWID_第4张图片

 


 

SQL> SELECT ROWID FROM SCOTT.EMP;

 

ROWID

------------------

AAAMfPAAEAAAAAgAAB

 

SQL>

 

SQL> select OBJECT_NAME,OBJECT_ID,DATA_OBJECT_ID,owner from dba_objects where object_name='EMP' and OWNER='SCOTT';

 

OBJECT_NAME          OBJECT_ID DATA_OBJECT_ID OWNER

-------------------- ---------- -------------- ----------

EMP                      51151         51151 SCOTT

 

SQL>

AAAMfP=12*64*64+31*64+15=51151

Select 12*64*64+31*64+15 from dual;

 

POWER(64,2)幂的用法

 

SQL> select 12*power(64,2) + 31*64+15 from dual;

 

12*POWER(64,2)+31*64+15

-----------------------

                 51151

 

SQL>

6.利用包得到ROWID信息

 

ROWID_第5张图片

 

 

select

 rowid,

 dbms_rowid.rowid_object(rowid) obj,

 dbms_rowid.rowid_relative_fno(rowid) fno,

 dbms_rowid.rowid_block_number(rowid) bno,

 dbms_rowid.rowid_row_number(rowid) rno

from emp

where rownum < 6;

 

ROWID                    OBJ       FNO       BNO       RNO

------------------ ---------- ---------- ---------- ----------

AAAM1jAABAAAO2SAAA      52579         1     60818         0

AAAM1jAABAAAO2SAAB     52579         1     60818         1

AAAM1jAABAAAO2SAAC     52579         1     60818         2

AAAM1jAABAAAO2SAAD     52579         1     60818         3

AAAM1jAABAAAO2SAAE     52579         1     60818         4

 

SQL>

 

7.根据ROWID四部分得到ROWID

 

SQL> select dbms_rowid.rowid_create(1,52579,1,60818,0) from dual; //第一个参数有两个值,0表示受限制的ROWID1表示扩展ROWID

 

DBMS_ROWID.ROWID_C

------------------

AAAM1jAABAAAO2SAAA

 

SQL>

 

 

你可能感兴趣的:(oracle,sql,数据库,object,table)