ORA-02429 Cannot Drop Index Used for Enforcement of Unique/Primary Key
ORA-02429: Cannot Drop Index Used for Enforcement of Unique/Primary Key
Section titled “ORA-02429: Cannot Drop Index Used for Enforcement of Unique/Primary Key”Error Overview
Section titled “Error Overview”Error Text: ORA-02429: cannot drop index used for enforcement of unique/primary key
The ORA-02429 error occurs when attempting to drop an index that is being used to enforce a PRIMARY KEY or UNIQUE constraint. Oracle creates and uses indexes to efficiently enforce uniqueness, and the index cannot be dropped while the constraint depends on it.
Common Causes
Section titled “Common Causes”1. Direct Index Drop Attempt
Section titled “1. Direct Index Drop Attempt”- Trying to DROP INDEX on constraint-backing index
- Not realizing index is tied to constraint
- Scripts attempting to rebuild by drop/create
2. Constraint-Index Confusion
Section titled “2. Constraint-Index Confusion”- Index created automatically with constraint
- Index created before constraint and adopted
- Unclear naming conventions
3. Cleanup or Maintenance
Section titled “3. Cleanup or Maintenance”- Attempting to reclaim space
- Index rebuild strategies
- Storage reorganization
4. Migration/Upgrade Activities
Section titled “4. Migration/Upgrade Activities”- Moving to different tablespace
- Changing index type
- Partition strategy changes
Diagnostic Queries
Section titled “Diagnostic Queries”Identify Constraint Using Index
Section titled “Identify Constraint Using Index”-- Find constraint associated with indexSELECT c.constraint_name, c.constraint_type, c.table_name, c.index_nameFROM user_constraints cWHERE c.index_name = UPPER('&index_name');
-- Find all constraints and their indexesSELECT table_name, constraint_name, constraint_type, index_name, statusFROM user_constraintsWHERE index_name IS NOT NULLORDER BY table_name, constraint_name;Check Index-Constraint Relationship
Section titled “Check Index-Constraint Relationship”-- Detailed view of index and constraintSELECT i.index_name, i.table_name, i.uniqueness, i.status as index_status, c.constraint_name, c.constraint_type, c.status as constraint_statusFROM user_indexes iLEFT JOIN user_constraints c ON i.index_name = c.index_nameWHERE i.index_name = UPPER('&index_name');
-- Check if index was created with constraint or separatelySELECT i.index_name, i.table_name, c.constraint_name, CASE WHEN i.index_name = c.constraint_name THEN 'CREATED WITH CONSTRAINT' ELSE 'CREATED SEPARATELY' END as originFROM user_indexes iJOIN user_constraints c ON i.index_name = c.index_nameWHERE c.constraint_type IN ('P', 'U');View Index Columns
Section titled “View Index Columns”-- See what columns the index coversSELECT index_name, column_name, column_positionFROM user_ind_columnsWHERE index_name = UPPER('&index_name')ORDER BY column_position;
-- Compare with constraint columnsSELECT c.constraint_name, cc.column_name, cc.positionFROM user_constraints cJOIN user_cons_columns cc ON c.constraint_name = cc.constraint_nameWHERE c.index_name = UPPER('&index_name')ORDER BY cc.position;Resolution Steps
Section titled “Resolution Steps”1. Drop the Constraint First
Section titled “1. Drop the Constraint First”-- If you want to remove both constraint and indexALTER TABLE table_name DROP CONSTRAINT constraint_name;-- Index is automatically dropped if it was created with the constraint
-- Verify index is goneSELECT index_name FROM user_indexesWHERE index_name = UPPER('&index_name');2. Drop Constraint with KEEP INDEX
Section titled “2. Drop Constraint with KEEP INDEX”-- Drop constraint but keep the index (as non-unique)ALTER TABLE table_name DROP CONSTRAINT constraint_name KEEP INDEX;
-- Now you can drop the index if neededDROP INDEX index_name;
-- Or rebuild it as neededALTER INDEX index_name REBUILD TABLESPACE new_tablespace;3. Disable Constraint, Manage Index, Re-enable
Section titled “3. Disable Constraint, Manage Index, Re-enable”-- Disable the constraintALTER TABLE table_name DISABLE CONSTRAINT constraint_name;
-- Now you can drop and recreate the indexDROP INDEX old_index_name;
CREATE UNIQUE INDEX new_index_nameON table_name (column1, column2)TABLESPACE new_tablespace;
-- Re-enable constraint using new indexALTER TABLE table_nameENABLE CONSTRAINT constraint_nameUSING INDEX new_index_name;4. Rebuild Index Without Dropping
Section titled “4. Rebuild Index Without Dropping”-- Rebuild in placeALTER INDEX index_name REBUILD;
-- Rebuild in different tablespaceALTER INDEX index_name REBUILD TABLESPACE new_tablespace;
-- Rebuild online (no blocking)ALTER INDEX index_name REBUILD ONLINE;
-- Rebuild with new storage parametersALTER INDEX index_name REBUILDTABLESPACE new_tablespaceSTORAGE (INITIAL 100M NEXT 50M);5. Move Index to Different Tablespace
Section titled “5. Move Index to Different Tablespace”-- Move constraint index to new tablespace-- Option A: Rebuild onlineALTER INDEX constraint_index REBUILD TABLESPACE new_ts ONLINE;
-- Option B: Drop and recreate constraint with new storageALTER TABLE table_name DROP CONSTRAINT pk_table;
CREATE UNIQUE INDEX pk_table_idxON table_name (id)TABLESPACE new_ts;
ALTER TABLE table_nameADD CONSTRAINT pk_table PRIMARY KEY (id)USING INDEX pk_table_idx;6. Replace with Different Index Type
Section titled “6. Replace with Different Index Type”-- Example: Replace B-tree with bitmap (for data warehouse)-- Note: Bitmap indexes cannot enforce constraints
-- For replacing with same type but different structure:ALTER TABLE table_name DROP CONSTRAINT pk_table;
-- Create new index with desired propertiesCREATE UNIQUE INDEX pk_table_newON table_name (id)TABLESPACE idx_tsCOMPRESS 1; -- Or other options
-- Recreate constraintALTER TABLE table_nameADD CONSTRAINT pk_table PRIMARY KEY (id)USING INDEX pk_table_new;Prevention Strategies
Section titled “Prevention Strategies”1. Name Indexes and Constraints Clearly
Section titled “1. Name Indexes and Constraints Clearly”-- Use clear naming conventionsCREATE TABLE employees ( id NUMBER, email VARCHAR2(100));
-- Create index first with clear nameCREATE UNIQUE INDEX idx_emp_id ON employees(id) TABLESPACE idx_ts;CREATE UNIQUE INDEX idx_emp_email ON employees(email) TABLESPACE idx_ts;
-- Create constraints using those indexesALTER TABLE employees ADD CONSTRAINT pk_employees PRIMARY KEY (id)USING INDEX idx_emp_id;
ALTER TABLE employees ADD CONSTRAINT uk_emp_email UNIQUE (email)USING INDEX idx_emp_email;2. Document Index-Constraint Relationships
Section titled “2. Document Index-Constraint Relationships”-- Generate documentationSELECT 'Table: ' || i.table_name || CHR(10) || ' Index: ' || i.index_name || ' (' || i.uniqueness || ')' || CHR(10) || ' Enforces: ' || NVL(c.constraint_name, 'No constraint') || CASE WHEN c.constraint_type IS NOT NULL THEN ' (' || c.constraint_type || ')' ELSE '' END as documentationFROM user_indexes iLEFT JOIN user_constraints c ON i.index_name = c.index_nameWHERE i.uniqueness = 'UNIQUE'ORDER BY i.table_name;3. Create Maintenance Procedures
Section titled “3. Create Maintenance Procedures”-- Safe index rebuild procedureCREATE OR REPLACE PROCEDURE safe_rebuild_index( p_index_name VARCHAR2, p_tablespace VARCHAR2 DEFAULT NULL) AS v_constraint_name VARCHAR2(128); v_table_name VARCHAR2(128); v_rebuild_sql VARCHAR2(500);BEGIN -- Check if index enforces a constraint BEGIN SELECT constraint_name, table_name INTO v_constraint_name, v_table_name FROM user_constraints WHERE index_name = UPPER(p_index_name);
DBMS_OUTPUT.PUT_LINE('Index enforces constraint: ' || v_constraint_name); DBMS_OUTPUT.PUT_LINE('Using REBUILD instead of DROP/CREATE'); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Index does not enforce any constraint'); END;
-- Build rebuild statement v_rebuild_sql := 'ALTER INDEX ' || p_index_name || ' REBUILD'; IF p_tablespace IS NOT NULL THEN v_rebuild_sql := v_rebuild_sql || ' TABLESPACE ' || p_tablespace; END IF; v_rebuild_sql := v_rebuild_sql || ' ONLINE';
-- Execute DBMS_OUTPUT.PUT_LINE('Executing: ' || v_rebuild_sql); EXECUTE IMMEDIATE v_rebuild_sql; DBMS_OUTPUT.PUT_LINE('Rebuild complete');END;/4. Use DBMS_METADATA for Scripting
Section titled “4. Use DBMS_METADATA for Scripting”-- Get complete DDL for constraint and indexSELECT DBMS_METADATA.GET_DDL('CONSTRAINT', constraint_name) as ddlFROM user_constraintsWHERE index_name = UPPER('&index_name');
SELECT DBMS_METADATA.GET_DDL('INDEX', '&index_name') as ddlFROM dual;Understanding Index-Constraint Relationship
Section titled “Understanding Index-Constraint Relationship”| Constraint Created | Index Behavior |
|---|---|
| Without USING INDEX | Auto-creates index with same name |
| USING INDEX idx_name | Uses existing index |
| DROP CONSTRAINT | Drops auto-created index; keeps USING INDEX |
| DROP CONSTRAINT KEEP INDEX | Keeps index (becomes non-unique for PK/UK) |
Related Errors
Section titled “Related Errors”- ORA-02449 - Unique/primary keys referenced by foreign keys
- ORA-02299 - Cannot validate constraint
- ORA-01408 - Such column list already indexed
- ORA-00955 - Name already used
Emergency Response
Section titled “Emergency Response”Quick Check Before DROP INDEX
Section titled “Quick Check Before DROP INDEX”-- Check if any constraint uses this indexSELECT constraint_name, constraint_type, table_nameFROM user_constraintsWHERE index_name = UPPER('&index_name');
-- If results returned, you must drop constraint first or use REBUILDRebuild Instead of Drop
Section titled “Rebuild Instead of Drop”-- Almost always, REBUILD achieves the goalALTER INDEX problem_index REBUILD ONLINE TABLESPACE new_ts;