os: centos 7.4
db: oracle 11.2.0.4
默认情况下,索引组织表所有非键列都存储在索引的叶块中。如果行数据非常宽,Btree的条目就可能会变得非常大。这样访问索引中同样多的条目就必须穿越更多的索引块,性能会受到很大影响。
把一些非键列值存储在索引组织表的 overflow 中,有助于提高索引组织表的btree索引的整体效率。
为索引组织表中行数据添加一个 overflow 可以通过 pctthreshold 和 including 参数来控制,两个参数可以同时设置。
pctthreshold
指定在何种条件下哪些列的数据要存储在 overflow,如果行的长度占索引块大小的百分比大小大于 pctthreshold 的值,那么每个超过阈值的列都将被存储在 overflow。
可以为 overflow 指定额外的 tablespace。
默认值是 50
including
指定将被存放在btree索引段的行数据的最后一个表列,including指定列之后的所有列,都将存储在 overflow。
版本
# cat /etc/centos-release
CentOS Linux release 7.4.1708 (Core)
#
# su - oracle
Last login: Tue Jan 21 03:40:05 CST 2020 on pts/0
$ sqlplus / as sysdba;
SQL*Plus: Release 11.2.0.4.0 Production on Mon Feb 3 10:29:09 2020
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options
SQL> set lines 300;
SQL> set pages 300;
SQL>
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE 11.2.0.4.0 Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production
SQL>
iot overflow
SQL> create table iot_t1 (
c0 varchar2(100),
c1 varchar2(100),
c2 varchar2(100),
c3 varchar2(100),
constraint pk_iot_t1 primary key (c0)
)
organization index
tablespace users
pctthreshold 40
including c2
overflow tablespace users
;
SQL> select to_char(dbms_metadata.get_ddl('TABLE','IOT_T1')) from dual;
TO_CHAR(DBMS_METADATA.GET_DDL('TABLE','IOT_T1'))
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE TABLE "SCOTT2"."IOT_T1"
( "C0" VARCHAR2(100),
"C1" VARCHAR2(100),
"C2" VARCHAR2(100),
"C3" VARCHAR2(100),
CONSTRAINT "PK_IOT_T1" PRIMARY KEY ("C0") ENABLE
) ORGANIZATION INDEX NOCOMPRESS PCTFREE 10 INITRANS 2 MAXTRANS 255 LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS"
PCTTHRESHOLD 40 INCLUDING "C2" OVERFLOW
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS"
查看下执行计划
SQL> insert into iot_t1
select level, dbms_random.string('a',100),dbms_random.string('a',100),dbms_random.string('a',100) from dual connect by level <=10000;
SQL>
SQL> set autotrace traceonly;
SQL>
SQL> select * from iot_t1 where c0='9998';
Execution Plan
----------------------------------------------------------
Plan hash value: 2714118034
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 208 | 1 (0)| 00:00:01 |
|* 1 | INDEX UNIQUE SCAN| PK_IOT_T1 | 1 | 208 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("C0"='9998')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
1017 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
SQL> set autotrace off;
SQL> select table_name,iot_name,iot_type from user_tables where table_name='IOT_T1' or iot_name='IOT_T1';
TABLE_NAME IOT_NAME IOT_TYPE
------------------------------ ------------------------------ ------------
SYS_IOT_OVER_479337 IOT_T1 IOT_OVERFLOW
IOT_T1 IOT
SQL> select index_name,index_type from user_indexes ui where 1=1 and table_name='IOT_T1';
INDEX_NAME INDEX_TYPE
------------------------------ ---------------------------
PK_IOT_T1 IOT - TOP
SQL> select segment_name,segment_type,bytes from user_segments us where us.segment_name in ('IOT_T0','PK_IOT_T0','SYS_IOT_OVER_479337');
SEGMENT_NAME SEGMENT_TYPE BYTES
--------------------------------------------------------------------------------- ------------------ ----------
PK_IOT_T0 INDEX 5242880
SYS_IOT_OVER_479337 TABLE 2097152
参考: