It is easy to create a default GLOBAL Index that is defined as a Unique Index on a column (or composite of columns) containing unique values.
But what if you have a Partitioned Table and want to create a LOCAL (i.e. equi-partitioned with the table) Index as a Unique Index ? Are there any constraints ?
Let me demonstrate a Partitioned table listing Users by Region Code.
But what if you have a Partitioned Table and want to create a LOCAL (i.e. equi-partitioned with the table) Index as a Unique Index ? Are there any constraints ?
Let me demonstrate a Partitioned table listing Users by Region Code.
SQL> create table users 2 (region_code varchar2(3), 3 username varchar2(30), 4 account_status varchar2(32), 5 created date, 6 profile varchar2(128)) 7 partition by range (region_code) 8 (partition a_m values less than ('N'), 9 partition n_r values less than ('S'), 10 partition s_z values less than (MAXVALUE)) 11 / Table created. SQL> SQL> insert into users 2 select substr(username,1,3), username, account_status, created, profile 3 from dba_users 4 / 39 rows created. SQL> SQL> commit; Commit complete. SQL> exec dbms_stats.gather_table_stats('','USERS'); PL/SQL procedure successfully completed. SQL> SQL> col partition_name format a30 SQL> select partition_name, num_rows 2 from user_tab_partitions 3 where table_name = 'USERS' 4 order by partition_position 5 / PARTITION_NAME NUM_ROWS ------------------------------ ---------- A_M 18 N_R 9 S_Z 12 SQL>
I now verify that I can create a GLOBAL (non-partitioned) Unique Index on USERNAME.
SQL> create unique index users_username_u1 on users(username) global; Index created. SQL> drop index users_username_u1; Index dropped. SQL> create unique index users_username_u1 on users(username); Index created. SQL> drop index users_username_u1; Index dropped. SQL>
I now verify that I can create a Non-Unique LOCAL Index (being equi-partitioned, the index is partitioned by REGION_CODE). (Being equi-partitioned, the default behaviour is the Index Partition Names inherit from the Table Partition Names).
SQL> create index users_username_l1 on users(username) local; Index created. SQL> select partition_name, num_rows 2 from user_ind_partitions 3 where index_name = 'USERS_USERNAME_L1' 4 order by partition_position 5 / PARTITION_NAME NUM_ROWS ------------------------------ ---------- A_M 18 N_R 9 S_Z 12 SQL> SQL> drop index users_username_l1; Index dropped. SQL>
I've proven (with the GLOBAL Index) that USERNAME is Unique across the whole table. Can I create a Unique LOCAL Index on this column ?
SQL> create unique index users_username_u_l1 on users(username) local; create unique index users_username_u_l1 on users(username) local * ERROR at line 1: ORA-14039: partitioning columns must form a subset of key columns of a UNIQUE index SQL>
Note the Error Message. The Partition Key must be a subset of the Unique Index columns. Let me try adding the Partition Key (in my example table, the Partition Key is a single column -- it could be a composite of multiple columns. In that case all the columns of the Partition Key must for a subset of the Unique Index).
SQL> create unique index users_rc_un_u_l1 on users(region_code, username) local; Index created. SQL> select partition_name, num_rows 2 from user_ind_partitions 3 where index_name = 'USERS_RC_UN_U_L1' 4 order by partition_position 5 / PARTITION_NAME NUM_ROWS ------------------------------ ---------- A_M 18 N_R 9 S_Z 12 SQL> drop index users_rc_un_u_l1; Index dropped. SQL> create unique index users_un_rc_u_l1 on users(username, region_code) local; Index created. SQL> select partition_name, num_rows 2 from user_ind_partitions 3 where index_name = 'USERS_UN_RC_U_L1' 4 order by partition_position 5 / PARTITION_NAME NUM_ROWS ------------------------------ ---------- A_M 18 N_R 9 S_Z 12 SQL>
It doesn't matter if I put the Partition Key (REGION_CODE) before or after the target column(s) (USERNAME) when I create the LOCAL Unique Index. What is necessary is that the Partition Key be a subset of the Unique Index definition.
.
.
.
2 comments:
Thanks Hemant for sharing this post.
Foued
there is a hidden trap - try this
insert into users select 'DBS', null, 'OPEN', sysdate, 'DEFAULT' from dual
1 Zeile eingefügt.
insert into users select 'DBS', null, 'OPEN', sysdate, 'DEFAULT' from dual
Fehler beim Start in Zeile: 1 in Befehl -
insert into users select 'DBS', null, 'OPEN', sysdate, 'DEFAULT' from dual
Fehlerbericht -
ORA-00001: Unique Constraint (ODS.USERS_RC_UN_U_L1) verletzt
the difference between a normal unique index and a prefixed local index is that in a normal (unpartitioned) index null values will not be stored :/
Post a Comment