In Partial Indexes Part I, we looked at how it was possible with the 12c database to create a Partial Index based on data from only selected table partitions. The resultant Partial Index can be either a Global or Local Index.
In Part I, we only really looked at Global Indexes, so let’s look at a Local Index example. Using the same Partitioned Table example as before:
SQL> create table pink_floyd (id number, status varchar2(6), name varchar2(30)) indexing off partition by range (id) (partition pf1 values less than (1000001), partition pf2 values less than (2000001) indexing off, partition pf3 values less than (maxvalue) indexing on); Table created.
This time, we’ll create a Local Partial Index:
SQL> create index pink_floyd_status_i on pink_floyd(status) local indexing partial; Index created.
If we look at the details of the resultant Local Index:
SQL> select index_name, partition_name, num_rows, status, leaf_blocks from dba_ind_partitions where index_name = 'PINK_FLOYD_STATUS_I'; INDEX_NAME PARTITION_NAME NUM_ROWS STATUS LEAF_BLOCKS -------------------- --------------- ---------- -------- ----------- PINK_FLOYD_STATUS_I PK1 0 UNUSABLE 0 PINK_FLOYD_STATUS_I PK2 0 UNUSABLE 0 PINK_FLOYD_STATUS_I PK3 1000000 USABLE 2513
We can see that for those table partitions with INDEXING OFF, the associated Local Indexes have simply been made UNUSABLE. Since Unusable Indexes consume no storage, there is effectively no corresponding index segment for these index partitions.
For the one and only PK3 table partition with INDEXING ON, its associated Local Index has been created as normal. So the end result is very similar to the previous Global Index example, only those rows from the table partitions with the INDEXING ON property are effectively being indexed.
There is one scenario in which the creation of a Partial Index is not permitted, that is in the creation of a Unique Index or a Non-Unique Index to police a Primary Key or Unique Key constraint. Some examples:
SQL> create unique index pink_floyd_id_i on pink_floyd(id) indexing partial; create unique index pink_floyd_id_i on pink_floyd(id) indexing partial * ERROR at line 1: ORA-14226: unique index may not be PARTIAL SQL> alter table pink_floyd add constraint pink_floyd_pk primary key(id) using index (create index pink_floyd_id_i on pink_floyd(id) indexing partial); alter table pink_floyd add constraint pink_floyd_pk primary key(id) using index (create index pink_floyd_id_i on pink_floyd(id) indexing partial) * ERROR at line 1: ORA-14196: Specified index cannot be used to enforce the constraint. SQL> create index pink_floyd_id_i on pink_floyd(id) indexing partial; Index created. SQL> alter table pink_floyd add primary key(id); alter table pink_floyd add primary key(id) * ERROR at line 1: ORA-01408: such column list already indexed
It clearly doesn’t make sense to create a Partial Unique Index or on a Non-Unique Index policing a PK or Unique Key constraint as it would be impossible to use such an index to guarantee the required unique property. With missing index entries associated with non-indexed partitions, how can Oracle determine whether a value from new row already exists or not ? It can’t and hence Oracle doesn’t permit the creation of such a Partial Index.
Partial Indexes can potentially be extremely useful in reducing unnecessary storage requirements, reducing index maintenance overheads and in improving performance by reducing index block accesses.
But they’re only useful (possible) with Partitioned Tables.
I’ll next look at another cool index improvement introduced with the Oracle 12c Database that’s associated with Partitioning, Asynchronous Global Index Maintenance …