本问题由之前的实验拓展遗留的一些疑问,详见:http://blog.itpub.net/30174570/viewspace-2140241/。
排除db_file_multiblock_read_count参数和动态采样(详见:http://blog.itpub.net/30174570/viewspace-2140240/)的影响。
操作系统环境:
-
[oracle@oracle ~]$ uname -a
-
Linux oracle.example.com 2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64 GNU/Linux
-
[oracle@oracle ~]$ lsb_release -a
-
LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
-
Distributor ID: RedHatEnterpriseServer
-
Description: Red Hat Enterprise Linux Server release 6.5 (Santiago)
-
Release: 6.5
- Codename: Santiago
数据库版本:
-
SYS@proc> select * from v$version where rownum=1;
-
-
BANNER
-
--------------------------------------------------------------------------------
- Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
构造测试数据:
-
SYS@proc> drop table t purge;
-
-
Table dropped.
-
-
SYS@proc> create table t as select * from dba_objects where rownum<=1200;
-
-
Table created.
-
-
SYS@proc> alter table t move tablespace test;
-
-
Table altered.
-
-
SYS@proc> select dbms_rowid.rowid_block_number(rowid) block#,min(rownum),max(rownum) from t group by dbms_rowid.rowid_block_number(rowid) order by dbms_rowid.rowid_block_number(rowid);
-
-
BLOCK# MIN(ROWNUM) MAX(ROWNUM)
-
---------- ----------- -----------
-
131 1 88
-
132 89 171
-
133 172 251
-
134 252 329
-
135 330 407
-
136 408 487
-
137 488 567
-
138 568 646
-
139 647 724
-
140 725 798
-
141 799 873
-
-
BLOCK# MIN(ROWNUM) MAX(ROWNUM)
-
---------- ----------- -----------
-
142 874 946
-
143 947 1022
-
145 1023 1104
-
146 1105 1179
-
147 1180 1200
-
-
16 rows selected.
-
-
SYS@proc> select EXTENT_ID,FILE_ID,BLOCK_ID,BLOCKS from dba_extents where owner='SYS' and SEGMENT_NAME='T';
-
-
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
-
---------- ---------- ---------- ----------
-
0 6 128 8 --128 129 130 131 132 133 134 135
-
1 6 136 8
- 2 6 144 8
引出问题:
-
SYS@proc> alter system set db_file_multiblock_read_count=1; --避免该参数的影响
-
-
System altered.
-
-
SYS@proc> show parameter db_file_multiblock_read_count
-
-
NAME TYPE VALUE
-
------------------------------------ ----------- ------------------------------
- db_file_multiblock_read_count integer 1
-
-
SYS@proc> analyze table t compute statistics; --避免动态采样的影响
-
-
Table analyzed.
-
-
SYS@proc> alter system flush buffer_cache;
-
-
System altered.
-
-
SYS@proc> select file#,dbablk,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='T') and state<>0 order by dbablk;
-
-
no rows selected
-
-
SYS@proc> select count(*) from t where rownum<=171;
-
-
COUNT(*)
-
----------
-
171
-
-
SYS@proc> select file#,dbablk,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='T') and state<>0 order by dbablk;
-
-
FILE# DBABLK STATE
-
---------- ---------- ----------
-
6 130 1
-
6 131 1
- 6 132 1
实验过程:
-
SYS@proc> alter system flush buffer_cache;
-
-
System altered.
-
-
SYS@proc> select file#,dbablk,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='T') and state<>0 order by dbablk;
-
-
no rows selected
-
-
SYS@proc> select HEADER_FILE,HEADER_BLOCK from dba_segments where owner='SYS' and segment_name='T'; --该语句可确定段头块是130
-
-
HEADER_FILE HEADER_BLOCK
-
----------- ------------
-
6 130
-
-
SYS@proc> select file#,dbablk,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='T') and state<>0 order by dbablk;
-
-
no rows selected
-
-
SYS@proc> select count(*) from t where rownum<=171;
-
-
COUNT(*)
-
----------
-
171
-
-
SYS@proc> set autotrace on
-
SYS@proc> select count(*) from t where rownum<=171;
-
-
COUNT(*)
-
----------
-
171
-
-
-
Execution Plan
-
----------------------------------------------------------
-
Plan hash value: 239743108
-
-
--------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-
--------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | 21 (0)| 00:00:01 |
-
| 1 | SORT AGGREGATE | | 1 | | |
-
|* 2 | COUNT STOPKEY | | | | |
-
| 3 | TABLE ACCESS FULL| T | 1200 | 21 (0)| 00:00:01 |
-
--------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
2 - filter(ROWNUM<=171)
-
-
-
Statistics
-
----------------------------------------------------------
-
0 recursive calls
-
0 db block gets
-
4 consistent gets
-
0 physical reads
-
0 redo size
-
527 bytes sent via SQL*Net to client
-
523 bytes received via SQL*Net from client
-
2 SQL*Net roundtrips to/from client
-
0 sorts (memory)
-
0 sorts (disk)
-
1 rows processed
-
-
SYS@proc> set autotrace off
-
SYS@proc> select file#,dbablk,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='T') and state<>0 order by dbablk;
-
-
FILE# DBABLK STATE
-
---------- ---------- ----------
-
6 130 1
-
6 131 1
- 6 132 1
为什么该处的逻辑读是4呢?全表扫描下,会跳过L1(块128)和L2(块129),直接读取段头L3和高水位线以下的所有块(为什么全表扫描只读了131和132,受到rownum的影响,详情见http://blog.itpub.net/30174570/viewspace-2140240/)。但是L3要读取两次,所以逻辑读为4。读取L3两次,一次读取Extent Map,一次读取Auxillary Map。
回到一开始的问题,Oracle通过读取L3段头块确定全表扫描应该读取的区和区中的数据块,这个就是为什么除了131和132这两个实际包含数据的数据块以外,还要读取130块的原因。
数据块130的部分dump信息:
-
Extent Control Header
-
-----------------------------------------------------------------
-
Extent Header:: spare1: 0 spare2: 0 #extents: 3 #blocks: 24
-
last map 0x00000000 #maps: 0 offset: 2716
-
Highwater:: 0x01800094 ext#: 2 blk#: 4 ext size: 8
-
#blocks in seg. hdr's freelists: 0
-
#blocks below: 20
-
mapblk 0x00000000 offset: 2
-
Unlocked
-
--------------------------------------------------------
-
Low HighWater Mark :
-
Highwater:: 0x01800094 ext#: 2 blk#: 4 ext size: 8
-
#blocks in seg. hdr's freelists: 0
-
#blocks below: 20
-
mapblk 0x00000000 offset: 2
-
Level 1 BMB for High HWM block: 0x01800090
-
Level 1 BMB for Low HWM block: 0x01800090
-
--------------------------------------------------------
-
Segment Type: 1 nl2: 1 blksz: 8192 fbsz: 0
-
L2 Array start offset: 0x00001434
-
First Level 3 BMB: 0x00000000
-
L2 Hint for inserts: 0x01800081
-
Last Level 1 BMB: 0x01800090
-
Last Level II BMB: 0x01800081
-
Last Level III BMB: 0x00000000
-
Map Header:: next 0x00000000 #extents: 3 obj#: 89405 flag: 0x10000000
-
Inc # 0
-
Extent Map
-
-----------------------------------------------------------------
-
0x01800080 length: 8
-
0x01800088 length: 8
-
0x01800090 length: 8
-
-
Auxillary Map
-
--------------------------------------------------------
-
Extent 0 : L1 dba: 0x01800080 Data dba: 0x01800083 "0x01800083"->二进制:00000001 10000000 00000000 10000011
-
Extent 1 : L1 dba: 0x01800080 Data dba: 0x01800088 前10位是文件号,后22位是块号,0000000110->文件号:6,000000 00000000 10000011->数据块:131
-
Extent 2 : L1 dba: 0x01800090 Data dba: 0x01800091
-
--------------------------------------------------------
-
-
Second Level Bitmap block DBAs
-
--------------------------------------------------------
-
DBA 1: 0x01800081
-
- End dump data blocks tsn: 9 file#: 6 minblk 130 maxblk 130
-
SYS@proc> select to_number('01800083','xxxxxxxx') from dual;
-
-
TO_NUMBER('01800083','XXXXXXXX')
-
--------------------------------
-
25165955
-
-
SYS@proc> select dbms_utility.data_block_address_file(25165955) from dual;
-
-
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(25165955)
-
----------------------------------------------
-
6
-
-
SYS@proc> select dbms_utility.data_block_address_block(25165955) from dual;
-
-
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(25165955)
-
-----------------------------------------------
- 131
其他拓展:
-
SYS@proc> --16进制数0x01800080转换为10进制数
-
SYS@proc> select to_number('01800080','xxxxxxxx') from dual;
-
-
TO_NUMBER('01800080','XXXXXXXX')
-
--------------------------------
-
25165952
-
-
SYS@proc> --10进制25165952转换为16进制
-
SYS@proc> select to_char(25165952,'xxxxxxxx') from dual;
-
-
TO_CHAR(2
-
---------
-
1800080
-
-
SYS@proc> --2进制转换为10进制
-
SYS@proc> select bin_to_num(1,1,0,1) a,bin_to_num(1,0) b from dual;
-
-
A B
-
---------- ----------
-
13 2
-
-
SYS@proc> select bin_to_num(1,1,1,0,1) from dual;
-
-
BIN_TO_NUM(1,1,1,0,1)
-
---------------------
- 29