Index-organized table
An index-organized table (IOT) is a type of table that stores data in a B*Tree index structure.
Normal relational tables, called heap-organized tables, store rows in any order (unsorted). In contrast to this, index-organized tables store rows in a B-tree index structure that is logically sorted in primary key order. Unlike normal primary key indexes, which store only the columns included in its definition, IOT indexes store all the columns of the table (see below for an exception to this rule - called the overflow area).
Properties and restrictions
- An IOT must contain a primary key.
- Rows are accessed via a logical rowid and not a physical rowid like in heap-organized tables.
- An IOT cannot be in a cluster.
- An IOT cannot contain a column of LONG data type.
- You cannot modify an IOT index property using ALTER INDEX (error ORA-25176), you must use an ALTER TABLE instead.
Advantages of an IOT
- As an IOT has the structure of an index and stores all the columns of the row, accesses via primary key conditions are faster as they don't need to access the table to get additional column values.
- As an IOT has the structure of an index and is thus sorted in the order of the primary key, accesses of a range of primary key values are also faster.
- As the index and the table are in the same segment, less storage space is needed.
- In addition, as rows are stored in the primary key order, you can further reduce space with key compression.
- As all indexes on an IOT uses logical rowids, they will not become unusable if the table is reorganized.
Row overflow area
If some columns of the table are infrequently accessed, it is possible to offload them into another segment named the overflow area. An overflow segment will decrease the size of the main (or top) segment and will increase the performance of statements that do not need access the columns in the overflow area. The overflow segments can reside in a tablespace different from the main segments.
Notes:
- The overflow area can contains only columns that are not part of the primary key.
- If a row cannot fit in a block, you must define an overflow area.
- Consequently, the primary key values of an IOT must fit in a single block.
The columns of the table that are recorded in the overflow segment are defined using the PCTHRESHOLD and/or INCLUDING options of the OVERFLOW clause (see example below).
Example of an IOT without an overflow area
The following example creates a simple IOT table and shows the objects and segments that are created. (This example was tested on Oracle versions 9.2 to 11.2.)
SQL> CREATE TABLE my_iot (id INTEGER PRIMARY KEY, value VARCHAR2(50)) 2 ORGANIZATION INDEX; Table created. SQL> SELECT table_name, iot_type, iot_name FROM user_tables; TABLE_NAME IOT_TYPE IOT_NAME ------------------------------ ------------ ------------------------------ MY_IOT IOT SQL> SELECT index_name, index_type, table_name FROM user_indexes; INDEX_NAME INDEX_TYPE TABLE_NAME ------------------------------ --------------------------- ------------------------------ SYS_IOT_TOP_71133 IOT - TOP MY_IOT SQL> SELECT object_id, object_name, object_type FROM user_objects ORDER BY 1; OBJECT_ID OBJECT_NAME OBJECT_TYPE ---------- -------------------- ------------------- 71133 MY_IOT TABLE 71134 SYS_IOT_TOP_71133 INDEX SQL> SELECT segment_name, segment_type FROM user_segments ORDER BY 1; SEGMENT_NAME SEGMENT_TYPE -------------------- ------------------ SYS_IOT_TOP_71133 INDEX
- Note: In 11g, you must use the following syntax to see the same output:
CREATE TABLE my_iot (id INTEGER PRIMARY KEY, value VARCHAR2(50)) SEGMENT CREATION IMMEDIATE ORGANIZATION INDEX;
- The reason for is that by default in 11g the segment is created only when the first row is inserted.
As you can see 2 objects are created: the table and the index, but there is only 1 segment (implementation of the object) which is the index one.
The name of the index is by default "SYS_IOT_TOP_<table object number>" and its type is "IOT - TOP". You can choose the name of your index using the following syntax:
SQL> CREATE TABLE my_iot (id INTEGER CONSTRAINT my_iot_pk PRIMARY KEY, value VARCHAR2(50)) 2 ORGANIZATION INDEX; Table created. SQL> SELECT table_name, iot_type, iot_name FROM user_tables; TABLE_NAME IOT_TYPE IOT_NAME ------------------------------ ------------ ------------------------------ MY_IOT IOT SQL> SELECT index_name, index_type, table_name FROM user_indexes; INDEX_NAME INDEX_TYPE TABLE_NAME ------------------------------ --------------------------- ------------------------------ MY_IOT_PK IOT - TOP MY_IOT SQL> SELECT object_id, object_name, object_type FROM user_objects ORDER BY 1; OBJECT_ID OBJECT_NAME OBJECT_TYPE ---------- -------------------- ------------------- 71135 MY_IOT TABLE 71136 MY_IOT_PK INDEX SQL> SELECT segment_name, segment_type FROM user_segments ORDER BY 1; SEGMENT_NAME SEGMENT_TYPE -------------------- ------------------ MY_IOT_PK INDEX
The IOT_NAME column is empty and will be useful in the example of the next section.
Example of an IOT with an overflow area
The following example creates an IOT with an overflow area and shows the objects and segments that are created. (This example was tested in versions 9.2 to 11.2, see the note in the previous section about 11g.)
SQL> CREATE TABLE my_iot (id INTEGER PRIMARY KEY, value VARCHAR2(50), comments varchar2(1000)) 2 ORGANIZATION INDEX 3 INCLUDING value OVERFLOW; Table created. SQL> SELECT table_name, iot_type, iot_name FROM user_tables ORDER BY 1; TABLE_NAME IOT_TYPE IOT_NAME ------------------------------ ------------ ------------------------------ MY_IOT IOT SYS_IOT_OVER_71142 IOT_OVERFLOW MY_IOT SQL> SELECT table_name, column_name FROM user_tab_columns ORDER by table_name, column_id; TABLE_NAME COLUMN_NAME ------------------------------ ------------------------------ MY_IOT ID MY_IOT VALUE MY_IOT COMMENTS SQL> SELECT index_name, index_type, table_name, include_column FROM user_indexes; INDEX_NAME INDEX_TYPE TABLE_NAME INCLUDE_COLUMN ------------------------------ --------------------------- ------------------------- -------------- SYS_IOT_TOP_71142 IOT - TOP MY_IOT 2 SQL> SELECT object_id, object_name, object_type FROM user_objects ORDER BY 1; OBJECT_ID OBJECT_NAME OBJECT_TYPE ---------- -------------------- ------------------- 71142 MY_IOT TABLE 71143 SYS_IOT_OVER_71142 TABLE 71144 SYS_IOT_TOP_71142 INDEX SQL> SELECT segment_name, segment_type FROM user_segments ORDER BY 1; SEGMENT_NAME SEGMENT_TYPE -------------------- ------------------ SYS_IOT_OVER_71142 TABLE SYS_IOT_TOP_71142 INDEX
All the columns up to and including the one named in the INCLUDING option of the OVERFLOW clause are in the top segment; the remaining ones are in the overflow segment.
Here, we see that 2 table objects are created, the main one is of iot_type IOT and the overflow one is of iot_type IOT_OVERFLOW. The name of the overflow table is SYS_IOT_OVER_<table object number>. You can see now the purpose of the IOT_NAME column, it gives the name of the IOT table for its overflow one.
You can also see that 2 segments are created: the index of the IOT and the overflow area.
In the end, the USER_INDEXES view gives you the last column included in the index in its INCLUDE_COLUMN column.
FAQ
How to move an IOT into another tablespace?
Based on the example used in the previous section:
SQL> SELECT segment_name, segment_type, tablespace_name FROM user_segments ORDER BY 1; SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME ------------------------------ ------------------ ------------------------------ SYS_IOT_OVER_71142 TABLE TS_D01 SYS_IOT_TOP_71142 INDEX TS_D01
Let's assume you want to move all the segments from their current tablespace to another tablespace. You'll quickly discover that you cannot use the standard commands:
SQL> ALTER TABLE sys_iot_over_71142 MOVE TABLESPACE ts_i01; ALTER TABLE sys_iot_over_71142 MOVE TABLESPACE ts_i01 * ERROR at line 1: ORA-25191: cannot reference overflow table of an index-organized table SQL> ALTER INDEX sys_iot_top_71142 REBUILD TABLESPACE ts_i01; ALTER INDEX sys_iot_top_71142 REBUILD TABLESPACE ts_i01 * ERROR at line 1: ORA-28650: Primary index on an IOT cannot be rebuilt
You have to first find the name of the associated IOT table:
SQL> SELECT iot_name FROM user_tables WHERE table_name = 'SYS_IOT_OVER_71142'; IOT_NAME ------------------------------ MY_IOT SQL> SELECT table_name FROM user_indexes WHERE index_name = 'SYS_IOT_TOP_71142'; TABLE_NAME ------------------------------ MY_IOT
Then you can move the segments:
SQL> ALTER TABLE my_iot MOVE TABLESPACE ts_i01; Table altered.
However, this is only the main part of the IOT - the overflow part continues to reside in its original tablespace:
SQL> SELECT segment_name, segment_type, tablespace_name FROM user_segments ORDER BY 1;
SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME ------------------------------ ------------------ ------------------------------ SYS_IOT_OVER_71142 TABLE TS_D01 SYS_IOT_TOP_71142 INDEX TS_I01
To move the overflow area also, an additional statement is necessary:
SQL> ALTER TABLE my_iot MOVE OVERFLOW TABLESPACE ts_i01; Table altered. SQL> SELECT segment_name, segment_type, tablespace_name FROM user_segments ORDER BY 1; SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME ------------------------------ ------------------ ------------------------------ SYS_IOT_OVER_71142 TABLE TS_I01 SYS_IOT_TOP_71142 INDEX TS_I01
Both steps can be combined in one statement:
SQL> ALTER TABLE my_iot MOVE TABLESPACE ts_d01 OVERFLOW TABLESPACE ts_d01; Table altered.
How to know which columns are in the overflow segment?
Remember that the INCLUDE_COLUMN of the USER_INDEXES view gives you the last column included in the index and so in the top segment, so joining this view with the USER_TAB_COLUMNS you can separate the columns that are in the top segment from those that are in the overflow one as with the following statement:
SQL> SELECT c.table_name, c.column_name, 2 CASE WHEN c.column_id <= i.include_column THEN 'TOP' ELSE 'OVERFLOW' END segment 3 FROM user_tab_columns c, user_indexes i 4 WHERE i.table_name = c.table_name 5 ORDER by table_name, column_id; TABLE_NAME COLUMN_NAME SEGMENT ------------------------------ ------------------------------ -------- MY_IOT ID TOP MY_IOT VALUE TOP MY_IOT COMMENTS OVERFLOW
Also see
Glossary of Terms | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z | # |