今天在看管理员手册的时候,Oracle提到了索引组织表列的顺序问题。于是做了个测试验证了一下。
由于索引组织表是根据索引的格式存储的表,所以主键的键值列应该存储在前面,随后才是表中的其他列,下面建立一个索引组织表,将主键列放在后面:
SQL> CREATE TABLE T_INDEX_ORG (NAME VARCHAR2(30), ID NUMBER PRIMARY KEY)
2 ORGANIZATION INDEX;
表已创建。
SQL> DESC T_INDEX_ORG
名称 是否为空? 类型
----------------------------------------------------------------- -------- ----------------
NAME VARCHAR2(30)
ID NOT NULL NUMBER
用DESC看NAME列排在主键列的前面,查询DBA_TAB_COLUMNS视图:
SQL> SELECT TABLE_NAME, COLUMN_NAME, COLUMN_ID
2 FROM USER_TAB_COLUMNS
3 WHERE TABLE_NAME = 'T_INDEX_ORG';
TABLE_NAME COLUMN_NAME COLUMN_ID
------------------------------ ------------------------------ ----------
T_INDEX_ORG NAME 1
T_INDEX_ORG ID 2
可以看到NAME列仍然在主键列的前面,难道Oracle在存储的时候真的先存储其他列,最后才是主键列吗,其实不然,这个列的顺序只是定义的顺序,真正的存储顺序需要查询COL$表:
SQL> COL OBJECT_NAME FORMAT A30
SQL> SELECT OBJECT_ID, OWNER, OBJECT_NAME
2 FROM DBA_OBJECTS
3 WHERE OBJECT_NAME = 'T_INDEX_ORG'
4 AND OWNER = USER;
OBJECT_ID OWNER OBJECT_NAME
---------- ------------------------------ ---------------
93348 YANGTK T_INDEX_ORG
SQL> SELECT OBJ#, COL#, SEGCOL#, NAME
2 FROM SYS.COL$
3 WHERE OBJ# = 93348;
OBJ# COL# SEGCOL# NAME
---------- ---------- ---------- ------------------------
93348 1 2 NAME
93348 2 1 ID
可以看到,SEGCOL#列表示的是存储时列的顺序,和预料的一样,对于索引组织表,Oracle会先存储主键列,然后是其他的非键值列。
除了索引组织表以外,还有一些可能导致列的定义与列的存储顺序不符,比如包含LONG列的情况。
Oracle的LONG列用于存放在表的最后一列:
SQL> CREATE TABLE T_LONG (ID NUMBER, C_LONG LONG, NAME VARCHAR2(30));
表已创建。
SQL> SELECT OBJECT_ID, OWNER, OBJECT_NAME
2 FROM DBA_OBJECTS
3 WHERE OBJECT_NAME = 'T_LONG'
4 AND OWNER = USER;
OBJECT_ID OWNER OBJECT_NAME
---------- ------------------------------ ----------------------------
93350 YANGTK T_LONG
SQL> SELECT OBJ#, COL#, SEGCOL#, NAME
2 FROM SYS.COL$
3 WHERE OBJ# = 93350;
OBJ# COL# SEGCOL# NAME
---------- ---------- ---------- ------------------------------
93350 1 1 ID
93350 2 3 C_LONG
93350 3 2 NAME
除了包含LONG的表,CLUSTER表也有同样的现象,CLUSTER的索引列在存储是排在第一位:
SQL> CREATE CLUSTER C_DEPT (DEPTNO NUMBER);
簇已创建。
SQL> CREATE TABLE DEPT (DEPT_NAME VARCHAR2(30), DEPT_NO NUMBER)
2 CLUSTER C_DEPT (DEPT_NO);
表已创建。
SQL> CREATE TABLE EMP (EMP_NO NUMBER, EMP_NAME VARCHAR2(30), DEPT_NO NUMBER)
2 CLUSTER C_DEPT (DEPT_NO);
表已创建。
SQL> SELECT OBJECT_ID, OWNER, OBJECT_NAME
2 FROM DBA_OBJECTS
3 WHERE OWNER = USER
4 AND OBJECT_NAME IN ('EMP', 'DEPT');
OBJECT_ID OWNER OBJECT_NAME
---------- ------------------------------ ------------------------------
93355 YANGTK DEPT 93356 YANGTK EMP
SQL> SELECT OBJ#, COL#, SEGCOL#, NAME
2 FROM SYS.COL$
3 WHERE OBJ# IN (93355, 93356);
OBJ# COL# SEGCOL# NAME
---------- ---------- ---------- ------------------------------
93355 1 2 DEPT_NAME
93355 2 1 DEPT_NO
93356 1 2 EMP_NO
93356 2 3 EMP_NAME
93356 3 1 DEPT_NO
同样HASH CLUSTER也具有相同的特性:
SQL> CREATE CLUSTER C_HASH (ID NUMBER)
2 HASHKEYS 100;
簇已创建。
SQL> CREATE TABLE T_HASH (NAME VARCHAR2(30), ID NUMBER)
2 CLUSTER C_HASH (ID);
表已创建。
SQL> SELECT OBJECT_ID, OWNER, OBJECT_NAME
2 FROM DBA_OBJECTS
3 WHERE OWNER = USER
4 AND OBJECT_NAME = 'T_HASH';
OBJECT_ID OWNER OBJECT_NAME
---------- ------------------------------ ----------------
93358 YANGTK T_HASH
SQL> SELECT OBJ#, COL#, SEGCOL#, NAME
2 FROM SYS.COL$
3 WHERE OBJ# = 93358;
OBJ# COL# SEGCOL# NAME
---------- ---------- ---------- -------------------------
93358 1 2 NAME
93358 2 1 ID
除了上面这些例子外,函数索引,嵌套表,对象表都会添加一些隐藏列,这些也会对列的存储顺序有所影响。