📑 Index Types & Creation
B-Tree Index (Standard)
-- Create simple B-tree index
CREATE INDEX idx_emp_salary
ON employees(salary)
PCTFREE 10
PCTUSED 60;
-- Create composite index (important for multi-column searches)
CREATE INDEX idx_emp_dept_salary
ON employees(dept_id, salary)
PCTFREE 10;
-- Create index with included columns (avoid table lookups)
CREATE INDEX idx_emp_sal_inc
ON employees(salary)
INCLUDE (name, email);
-- Drop index
DROP INDEX idx_emp_salary;
-- View indexes
SELECT index_name, table_name, uniqueness
FROM user_indexes;
Bitmap Index
-- Create bitmap index for low cardinality columns
CREATE BITMAP INDEX idx_emp_gender
ON employees(gender);
-- Create composite bitmap index
CREATE BITMAP INDEX idx_emp_status_dept
ON employees(emp_status, dept_id);
-- Useful for:
-- - Few distinct values (M/F, Active/Inactive)
-- - OLAP workloads, data warehousing
-- - Complex WHERE clauses with AND/OR
🔧 Function-Based Indexes
Expression & Function Indexes
-- Create function-based index (UPPER function)
CREATE INDEX idx_emp_name_upper
ON employees(UPPER(name));
-- Now this query uses the index:
SELECT * FROM employees
WHERE UPPER(name) = 'JOHN';
-- Function-based with expression
CREATE INDEX idx_emp_annual_salary
ON employees(salary * 12);
-- Case expression index
CREATE INDEX idx_emp_category
ON employees(
CASE
WHEN salary > 100000 THEN 'SENIOR'
WHEN salary > 50000 THEN 'MID'
ELSE 'JUNIOR'
END
);
-- JSON search index (Oracle 12.2+)
CREATE INDEX idx_doc_search
ON documents(json_col) INDEXTYPE IS CTXSYS.CONTEXT;
📊 Index Management & Monitoring
Index Statistics & Maintenance
| Operation | Purpose | Example |
|---|---|---|
| REBUILD | Reconstruct index, remove fragmentation | ALTER INDEX idx_name REBUILD; |
| COALESCE | Merge leaf blocks, maintain online | ALTER INDEX idx_name COALESCE; |
| MONITORING | Track index usage statistics | ALTER INDEX idx_name MONITORING USAGE; |
| SHRINK | Reduce allocated space | ALTER INDEX idx_name SHRINK SPACE; |
| UNUSABLE | Mark index offline | ALTER INDEX idx_name UNUSABLE; |
Index Usage & Performance
-- Monitor index usage
ALTER INDEX idx_emp_salary MONITORING USAGE;
-- View index statistics
SELECT index_name, blevel, leaf_blocks, distinct_keys
FROM user_ind_statistics
WHERE index_name = 'IDX_EMP_SALARY';
-- Check index fragmentation
SELECT index_name, del_lf_rows, lf_rows,
ROUND(100 * del_lf_rows / lf_rows, 2) fragmentation_pct
FROM user_ind_statistics
WHERE lf_rows > 0;
-- Find unused indexes
SELECT i.index_name, i.table_name
FROM user_indexes i
LEFT JOIN v$object_usage v ON i.index_name = v.name
WHERE v.name IS NULL;
-- Rebuild fragmented index
ALTER INDEX idx_emp_salary REBUILD ONLINE;
⚡ Index Design Best Practices
Indexing Strategies
-- Leading column is most selective
CREATE INDEX idx_emp_composite
ON employees(
dept_id, -- Most selective first
salary, -- Second
hire_date -- Least selective
);
-- Separate indexes vs composite
-- When to use composite:
-- - Frequently used together in WHERE clause
-- - Covering index can avoid table access
-- Partial index (filter on subset of rows)
CREATE INDEX idx_emp_active
ON employees(emp_id)
WHERE status = 'ACTIVE';
-- Invisible index (test without rebuilding)
CREATE INDEX idx_emp_test
ON employees(salary)
INVISIBLE;
-- Make index visible
ALTER INDEX idx_emp_test VISIBLE;
💡 Index Best Practices: Index columns in WHERE clauses. Use composite indexes for
frequently joined queries. Avoid indexes on low cardinality columns (use bitmap). Remove unused indexes.
Monitor index fragmentation. Rebuild when fragmentation > 20%. Use function-based indexes for
UPPER/LOWER searches. Consider selectivity (0-100%) when choosing columns. Limit indexes per table
(usually 3-5 sufficient).
✓ Learning Checklist - Module 14