select * from tab的顺序——rowid和块的扫描

无论执行多少次select * from tab,它的结果总是一致的(不考虑期间表有数据变化)。

无论是请不清理内存,无论是磁盘读还是直接从内存中读取,结果总是一致。

所以为什么它的结果是“有序”的,是按什么方式“有序”。

 

回答上面的问题我们要了解2个概念

1.全表扫描。select * from tab是全表扫描,全表扫描是从该segment的第一个extent的第一个block开始扫描,一直扫描到表的高水位。

2.rowid。rowid是已文件号,块号,行号来标志数据行的。rowid的递增参考我之前的文章https://blog.csdn.net/qq_40687433/article/details/78466488

所以,如果是全表扫描,那么是不是一定是以rowid的顺序扫描?

3.多块读。单块读,多块读可参考我之前的文章https://blog.csdn.net/qq_40687433/article/details/82180638

多块读一次从磁盘读取多个块到buffer cache中,且buffer不连续,块必须是scattered(零散地)分布在内存中。

这好像会让结果趋于“无序”,因为每次都是零散的读,不连续的。

 

实验一:

1.rowid是否可用被重用

第一部分,删除一条记录后,不提交,插入一条数据,那么改数据应该算第一行,那么rowid是否重用呢?

SQL> create table testr(col1 number);

Table created.

SQL> insert into testr values(1);

1 row created.

SQL> commit;

Commit complete.

SQL> select rowid from testr;

ROWID
------------------
AAAGTsAABAAAQuBAAA

1 row selected.

SQL> delete from testr;

1 row deleted.

SQL> insert into testr values(2);

1 row created.

SQL>  select rowid from testr;

ROWID
------------------
AAAGTsAABAAAQuBAAB

1 row selected.

rowid是AAB,是第二行。其实没有提交的话,改记录并没有被标注为失效的,记录仍然存在,所以新插入数据当然不能覆盖之前的记录。

第二部分,commit后,rowid是否重用

SQL> delete from testr;

1 row deleted.

SQL> commit;

Commit complete.

SQL> insert into testr values(3);

1 row created.

SQL> commit;

Commit complete.

SQL> select rowid from testr;

ROWID
------------------
AAAGTsAABAAAQuBAAA

1 row selected.

新插入的数据,在这个块里面,确实属于第一行。所以rowid被重用.

番外测试:

SQL> insert  into testr values(4);

1 row created.

SQL> commit;

Commit complete.

SQL> select rowid,dbms_rowid.rowid_row_number(rowid) from testr;

ROWID              DBMS_ROWID.ROWID_ROW_NUMBER(ROWID)
------------------ ----------------------------------
AAAGTsAABAAAQuBAAA                                  0
AAAGTsAABAAAQuBAAC                                  2

testr中只有2行,第二行不是AAB而是AAC。所以rowid中的行号并不等于记录行号(为什么会跳过1呢,先放在这,后面再做trace研究)

(关于rowid跳跃请参考https://blog.csdn.net/qq_40687433/article/details/88868112)

 

其实上面的实验并不影响我们刚才设想的rowid排序的预期结果。因为rowid本身是递增的。

 

实验二:

通过创建大表,通过select * from tab对比select * from tab order by rowid是否有差异,来验证我们之前的疑问。

脚本:

[oracle@cs-db htz]$ cat rowid_test.sh
sqlplus / as sysdba< alter system flush buffer_cache;
set lin 200;
set echo off;
SET SERVEROUTPUT off;
set feedback off;
select rowid,object_name from tab1_rowid;
!
[oracle@cs-db htz]$ cat rowid_test2.sh
sqlplus / as sysdba< alter system flush buffer_cache;
set lin 200;
set echo off;
SET SERVEROUTPUT off;
set feedback off;
select rowid,object_name from tab1_rowid order by rowid;
!

执行sh rowid_test.sh>aa.txt ,

然后alter system flush buffer_cache刷新buffer cache,让oracle再去走dbfile scatter read(可以开10046,确保2个查询都是走的多块读)

执行sh rowid_test2.sh >>bb.txt

执行diff aa.txt bb.txt  没有任何输出,说明结果是一致的。说明select * from tab的结果是按rowid排序的。

 

实验结果已经出来了。事实胜于雄辩,select * from tab的结果是按rowid排序的。

但是我仍然有些疑问

1.我们考虑的环境太少。从select * from tab的执行到返回结果到客户端。我们只考虑了oracle怎么把数据读到buffer cache,并没有考虑怎么把数据传递到pga,更没有考虑到pga返回到客户端进程。

2.如果说多块读这么的无序,结果为何如此的有序呢

你可能感兴趣的:(ORACLE,BASIC)