[20231024]NULL值在索引的情况.txt
[20231024]NULL值在索引的情况.txt
--//如果全部键值是NULL,oracle不保存该键值在索引中.如果表后面几个字段是NULL值,oracle不会浪费空间保存相关信息.
--//因为在数据块中存在一个保存字段数量的标识,而索引块不存在这个标识。这样对于索引字段最后几个字段为NULL的情况,oracle是
--//如何操作的呢? 如果索引尾部几个字段是NULL呢?以前没有关注这个问题,测试看看.
1.环境:
SCOTT@test01p> @ver1
PORT_STRING VERSION BANNER CON_ID
------------------------------ -------------- -------------------------------------------------------------------------------- ----------
IBMPC/WIN_NT64-9.1.0 12.2.0.1.0 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production 0
2.测试:
SCOTT@test01p> create table empx as select * from emp;
Table created.
SCOTT@test01p> create unique index pk_empx on empx (empno,comm);
Index created.
SCOTT@test01p> select * from empx order by 1;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30
7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10
14 rows selected.
--//我按照empno排序,这样kd_off[2]指向的就是empno的最小键值。
SCOTT@test01p> @ seg2 pk_empx
SCOTT@test01p> @ pr
==============================
SEG_MB : 0
SEG_OWNER : SCOTT
SEG_SEGMENT_NAME : PK_EMPX
SEG_PARTITION_NAME :
SEG_SEGMENT_TYPE : INDEX
SEG_TABLESPACE_NAME : USERS
BLOCKS : 8
HDRFIL : 11
HDRBLK : 410
PL/SQL procedure successfully completed.
--//dba =11,411 就是索引的root,empx表仅仅14条记录,该地址也同时是叶子节点.
3.bbed观察:
BBED> set dba 11,412
DBA 0x02c0019c (46137756 11,412)
--//windwos bbed版本 块偏移+1 ,因为无法识别12c的数据文件OS头.
BBED> map
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P (11)
Block: 412 Dba:0x02c0019c
------------------------------------------------------------
KTB Data Block (Index Leaf)
struct kcbh, 20 bytes @0
struct ktbbh, 72 bytes @20
struct kdxle, 32 bytes @100
b2 kd_off[14] @132
ub1 freespace[7784] @160
ub1 rowdata[188] @7944
ub4 tailchk @8188
BBED> map
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P (11)
Block: 412 Dba:0x02c0019c
------------------------------------------------------------
KTB Data Block (Index Leaf)
struct kcbh, 20 bytes @0
struct ktbbh, 72 bytes @20
struct kdxle, 32 bytes @100
b2 kd_off[14] @132
ub1 freespace[7805] @160
ub1 rowdata[167] @7965
ub4 tailchk @8188
BBED> p kdxle
struct kdxle, 32 bytes @100
struct kdxlexco, 16 bytes @100
ub1 kdxcolev @100 0x00
ub1 kdxcolok @101 0x00
ub1 kdxcoopc @102 0x80
ub1 kdxconco @103 0x02 --//索引包含2个字段.如果上面建立的索引非唯一,这里是3,
--//包括rowid相关信息作为索引的一部分
ub4 kdxcosdc @104 0x00000000
sb2 kdxconro @108 14 --//14条记录.
b2 kdxcofbo @110 64
b2 kdxcofeo @112 7848
b2 kdxcoavs @114 7784
b2 kdxlespl @116 0
sb2 kdxlende @118 0
ub4 kdxlenxt @120 0x00000000
ub4 kdxleprv @124 0x00000000
ub1 kdxledsz @128 0x06 --//索引的rowid在前面,没有长度指示器,占6字节.
--//如果是0,非唯一索引。是10是全局唯一索引。
--//是8是cluster index。
ub1 kdxleunuse @129 0x00
BBED> p kd_off
b2 kd_off[0] @132 8036 --//8036+100(kdxle的偏移)=8136 表示索引的结尾,中间还保留
--//8188-8136 = 52,不知道什么用处。
b2 kd_off[1] @134 0 --//kd_off[0],kd_off[1]执行的偏移不对,我估计oracle改变了
--//kdxle结构,这4个字节的内容属于kdxle。
b2 kd_off[2] @136 8023
b2 kd_off[3] @138 8008
b2 kd_off[4] @140 7993
b2 kd_off[5] @142 7980
b2 kd_off[6] @144 7965
b2 kd_off[7] @146 7952
b2 kd_off[8] @148 7939
b2 kd_off[9] @150 7926
b2 kd_off[10] @152 7913
b2 kd_off[11] @154 7899
b2 kd_off[12] @156 7886
b2 kd_off[13] @158 7874
--//以前提过kd_off指向的键值是按照键值排序的.注意bbed的版本有问题,实际上从kd_off[2]开始.
BBED> x /rnnn *kd_off[2]
rowdata[179] @8123
------------
flag@8123: 0x00 (NONE)
lock@8124: 0x00
keydata[6]: 0x02 0xc0 0x01 0x93 0x00 0x00
data key:
col 0[3] @8132: 7369
col 1[0] @8136: *NULL*
--//8123+1+1+6+1+3+1 = 8136
--//8188-8136 = 52,确实保留52字节在数据块尾部,为什么?
BBED> x /rnnn *kd_off[3]
rowdata[164] @8108
------------
flag@8108: 0x00 (NONE)
lock@8109: 0x00
keydata[6]: 0x02 0xc0 0x01 0x93 0x00 0x01
data key:
col 0[3] @8117: 7499
col 1[2] @8121: 300
--//选择16进制看看.
BBED> x /rxxx *kd_off[2]
rowdata[179] @8123
------------
flag@8123: 0x00 (NONE)
lock@8124: 0x00
keydata[6]: 0x02 0xc0 0x01 0x93 0x00 0x00
data key:
col 0[3] @8132: 0xc2 0x4a 0x46
col 1[0] @8136: *NULL*
BBED> p tailchk
ub4 tailchk @8188 0xb5370601
BBED> dump /v offset 8123 count 100
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF (11)
Block: 412 Offsets: 8123 to 8191 Dba:0x02c0019c
-------------------------------------------------------
000002c0 01930000 03c24a46 ff000000 l ...?....翵F....
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00010637 b5 l ...7
<16 bytes per line>
BBED> dump /v offset 8123 count 13
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF (11)
Block: 412 Offsets: 8123 to 8135 Dba:0x02c0019c
-------------------------------------------------------
000002c0 01930000 03c24a46 ff l ...?....翵F.
<16 bytes per line>
--//可以发现NULL保存的信息0xff,前面没有长度指示器。有点奇怪为什么索引在底部保留一段没有保存信息,占用52字节.
BBED> x /rxxx *kd_off[5]
rowdata[136] @8080
------------
flag@8080: 0x00 (NONE)
lock@8081: 0x00
keydata[6]: 0x02 0xc0 0x01 0x93 0x00 0x03
data key:
col 0[3] @8089: 0xc2 0x4c 0x43
col 1[0] @8093: *NULL*
BBED> dump /v offset 8080 count 13
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF (11)
Block: 412 Offsets: 8080 to 8092 Dba:0x02c0019c
-------------------------------------------------------
000002c0 01930003 03c24c43 ff l ...?....翷C.
<16 bytes per line>
--//也就是索引是保留NULL值的,即使在索引字段的尾部。
--//如果全部键值是NULL,oracle不保存该键值在索引中.如果表后面几个字段是NULL值,oracle不会浪费空间保存相关信息.
--//因为在数据块中存在一个保存字段数量的标识,而索引块不存在这个标识。这样对于索引字段最后几个字段为NULL的情况,oracle是
--//如何操作的呢? 如果索引尾部几个字段是NULL呢?以前没有关注这个问题,测试看看.
1.环境:
SCOTT@test01p> @ver1
PORT_STRING VERSION BANNER CON_ID
------------------------------ -------------- -------------------------------------------------------------------------------- ----------
IBMPC/WIN_NT64-9.1.0 12.2.0.1.0 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production 0
2.测试:
SCOTT@test01p> create table empx as select * from emp;
Table created.
SCOTT@test01p> create unique index pk_empx on empx (empno,comm);
Index created.
SCOTT@test01p> select * from empx order by 1;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30
7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10
14 rows selected.
--//我按照empno排序,这样kd_off[2]指向的就是empno的最小键值。
SCOTT@test01p> @ seg2 pk_empx
SCOTT@test01p> @ pr
==============================
SEG_MB : 0
SEG_OWNER : SCOTT
SEG_SEGMENT_NAME : PK_EMPX
SEG_PARTITION_NAME :
SEG_SEGMENT_TYPE : INDEX
SEG_TABLESPACE_NAME : USERS
BLOCKS : 8
HDRFIL : 11
HDRBLK : 410
PL/SQL procedure successfully completed.
--//dba =11,411 就是索引的root,empx表仅仅14条记录,该地址也同时是叶子节点.
3.bbed观察:
BBED> set dba 11,412
DBA 0x02c0019c (46137756 11,412)
--//windwos bbed版本 块偏移+1 ,因为无法识别12c的数据文件OS头.
BBED> map
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P (11)
Block: 412 Dba:0x02c0019c
------------------------------------------------------------
KTB Data Block (Index Leaf)
struct kcbh, 20 bytes @0
struct ktbbh, 72 bytes @20
struct kdxle, 32 bytes @100
b2 kd_off[14] @132
ub1 freespace[7784] @160
ub1 rowdata[188] @7944
ub4 tailchk @8188
BBED> map
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P (11)
Block: 412 Dba:0x02c0019c
------------------------------------------------------------
KTB Data Block (Index Leaf)
struct kcbh, 20 bytes @0
struct ktbbh, 72 bytes @20
struct kdxle, 32 bytes @100
b2 kd_off[14] @132
ub1 freespace[7805] @160
ub1 rowdata[167] @7965
ub4 tailchk @8188
BBED> p kdxle
struct kdxle, 32 bytes @100
struct kdxlexco, 16 bytes @100
ub1 kdxcolev @100 0x00
ub1 kdxcolok @101 0x00
ub1 kdxcoopc @102 0x80
ub1 kdxconco @103 0x02 --//索引包含2个字段.如果上面建立的索引非唯一,这里是3,
--//包括rowid相关信息作为索引的一部分
ub4 kdxcosdc @104 0x00000000
sb2 kdxconro @108 14 --//14条记录.
b2 kdxcofbo @110 64
b2 kdxcofeo @112 7848
b2 kdxcoavs @114 7784
b2 kdxlespl @116 0
sb2 kdxlende @118 0
ub4 kdxlenxt @120 0x00000000
ub4 kdxleprv @124 0x00000000
ub1 kdxledsz @128 0x06 --//索引的rowid在前面,没有长度指示器,占6字节.
--//如果是0,非唯一索引。是10是全局唯一索引。
--//是8是cluster index。
ub1 kdxleunuse @129 0x00
BBED> p kd_off
b2 kd_off[0] @132 8036 --//8036+100(kdxle的偏移)=8136 表示索引的结尾,中间还保留
--//8188-8136 = 52,不知道什么用处。
b2 kd_off[1] @134 0 --//kd_off[0],kd_off[1]执行的偏移不对,我估计oracle改变了
--//kdxle结构,这4个字节的内容属于kdxle。
b2 kd_off[2] @136 8023
b2 kd_off[3] @138 8008
b2 kd_off[4] @140 7993
b2 kd_off[5] @142 7980
b2 kd_off[6] @144 7965
b2 kd_off[7] @146 7952
b2 kd_off[8] @148 7939
b2 kd_off[9] @150 7926
b2 kd_off[10] @152 7913
b2 kd_off[11] @154 7899
b2 kd_off[12] @156 7886
b2 kd_off[13] @158 7874
--//以前提过kd_off指向的键值是按照键值排序的.注意bbed的版本有问题,实际上从kd_off[2]开始.
BBED> x /rnnn *kd_off[2]
rowdata[179] @8123
------------
flag@8123: 0x00 (NONE)
lock@8124: 0x00
keydata[6]: 0x02 0xc0 0x01 0x93 0x00 0x00
data key:
col 0[3] @8132: 7369
col 1[0] @8136: *NULL*
--//8123+1+1+6+1+3+1 = 8136
--//8188-8136 = 52,确实保留52字节在数据块尾部,为什么?
BBED> x /rnnn *kd_off[3]
rowdata[164] @8108
------------
flag@8108: 0x00 (NONE)
lock@8109: 0x00
keydata[6]: 0x02 0xc0 0x01 0x93 0x00 0x01
data key:
col 0[3] @8117: 7499
col 1[2] @8121: 300
--//选择16进制看看.
BBED> x /rxxx *kd_off[2]
rowdata[179] @8123
------------
flag@8123: 0x00 (NONE)
lock@8124: 0x00
keydata[6]: 0x02 0xc0 0x01 0x93 0x00 0x00
data key:
col 0[3] @8132: 0xc2 0x4a 0x46
col 1[0] @8136: *NULL*
BBED> p tailchk
ub4 tailchk @8188 0xb5370601
BBED> dump /v offset 8123 count 100
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF (11)
Block: 412 Offsets: 8123 to 8191 Dba:0x02c0019c
-------------------------------------------------------
000002c0 01930000 03c24a46 ff000000 l ...?....翵F....
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00010637 b5 l ...7
<16 bytes per line>
BBED> dump /v offset 8123 count 13
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF (11)
Block: 412 Offsets: 8123 to 8135 Dba:0x02c0019c
-------------------------------------------------------
000002c0 01930000 03c24a46 ff l ...?....翵F.
<16 bytes per line>
--//可以发现NULL保存的信息0xff,前面没有长度指示器。有点奇怪为什么索引在底部保留一段没有保存信息,占用52字节.
BBED> x /rxxx *kd_off[5]
rowdata[136] @8080
------------
flag@8080: 0x00 (NONE)
lock@8081: 0x00
keydata[6]: 0x02 0xc0 0x01 0x93 0x00 0x03
data key:
col 0[3] @8089: 0xc2 0x4c 0x43
col 1[0] @8093: *NULL*
BBED> dump /v offset 8080 count 13
File: D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF (11)
Block: 412 Offsets: 8080 to 8092 Dba:0x02c0019c
-------------------------------------------------------
000002c0 01930003 03c24c43 ff l ...?....翷C.
<16 bytes per line>
--//也就是索引是保留NULL值的,即使在索引字段的尾部。
分类:
oracle
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
2018-10-30 [20181031]12c 在线移动数据文件.txt