Loading learning content...
You've learned what clustered and non-clustered indexes are, how they work internally, and why only one clustered index per table is possible. Now comes the practical challenge every database professional faces: When should you use each type?
Index selection is both art and science. The science involves understanding I/O patterns, analyzing query workloads, and calculating storage overhead. The art involves weighing competing requirements, anticipating future access patterns, and making judgment calls when data is incomplete.
This page synthesizes everything we've learned into actionable selection criteria. We'll examine specific scenarios, provide decision frameworks, and equip you with the knowledge to make confident indexing decisions for any database design challenge.
By the end of this page, you will have clear criteria for when to use clustered vs non-clustered indexes, understand the trade-offs in common scenarios, possess a systematic decision framework for index selection, and be able to evaluate indexing strategies for production database designs.
Before diving into specific scenarios, let's establish the fundamental principles that guide index selection. These principles emerge from the physical characteristics we've studied.
Principle 1: Clustered for Range, Non-Clustered for Point
The clustered index's primary advantage is sequential I/O for range scans. Non-clustered indexes are efficient for point lookups (especially with covering). This leads to a fundamental guideline:
| Query Pattern | Clustered Efficiency | Non-Clustered Efficiency | Recommendation |
|---|---|---|---|
| Single row by key | ★★★★★ | ★★★★☆ (if covering) | Either works well |
| Range scan (1-5%) | ★★★★★ | ★★☆☆☆ (many lookups) | Clustered strongly preferred |
| Range scan (>10%) | ★★★★★ | ★☆☆☆☆ (scan likely) | Clustered or full scan |
| Multiple point lookups | ★★★★☆ | ★★★★★ (index union) | Non-clustered with covering |
| Full table scan | ★★★★☆ (ordered) | N/A | Neither helps; consider partitioning |
| ORDER BY match | ★★★★★ (free sort) | ★★★☆☆ (index scan) | Clustered if dominant pattern |
Principle 2: One Clustered, Many Non-Clustered
You get exactly one clustered index—use it for the most impactful access pattern. Use non-clustered indexes to support additional access patterns:
Principle 3: Balance Read and Write
Every index has maintenance cost. The trade-off:
The clustered index is maintained on every write regardless. Non-clustered indexes add incremental write overhead proportional to their count and width.
For OLTP tables, aim for 5 or fewer indexes total (including clustered). Each additional index beyond 5 should require explicit justification. For OLAP/reporting tables where writes are rare, more indexes are acceptable. For staging/ETL tables, often zero non-clustered indexes is optimal.
Principle 4: Consider Index Width
Both clustered and non-clustered index width matters:
Narrower is almost always better. Wide keys reduce fanout, increase tree height, and consume more storage.
The clustered index key should satisfy as many of these criteria as possible. No key will satisfy all perfectly—prioritize based on your workload.
Scoring Matrix Example:
Consider an Orders table with candidate keys:
| Criterion | Weight | OrderID (INT) | OrderDate | CustomerID | (CustomerID, OrderDate) |
|---|---|---|---|---|---|
| Unique | 2 | ✓✓ | ✗ | ✗ | ✓✓ |
| Narrow | 2 | ✓✓ | ✓ | ✓ | ✓ |
| Static | 3 | ✓✓✓ | ✓✓ | ✓ | ✓✓ |
| Ever-increasing | 2 | ✓✓ | ✓✓ | ✗ | ✗ |
| Range-scanned | 3 | ✗ | ✓✓✓ | ✓ | ✓✓ |
| ORDER BY match | 1 | ✗ | ✓ | ✓ | ✓ |
| Total Score | 11 | 12 | 7 | 11 |
In this example, OrderDate clusters well for date-range reporting; (CustomerID, OrderDate) works if customer+date queries dominate; OrderID is the safe default.
Never cluster on: (1) Frequently updated columns. (2) Random values like UUIDv4. (3) Wide TEXT/VARCHAR columns. (4) Low-cardinality columns (Status, Type). (5) Composite keys with 4+ columns. These cause excessive fragmentation, overhead, or poor selectivity.
Non-clustered indexes should be created strategically to support specific query patterns without creating excessive write overhead.
Create a Non-Clustered Index When:
Avoid Creating Non-Clustered Indexes When:
Non-Clustered Index Design Checklist:
| Question | Consideration |
|---|---|
| Which columns to index? | Start with WHERE clause columns in critical queries |
| Column order in composite? | Most selective column first; leftmost prefix rule applies |
| Include INCLUDEd columns? | Add columns to eliminate lookups for specific queries |
| Ascending or descending? | Match ORDER BY; affects backward scans |
| Filtered index? | WHERE clause on index for partial data (e.g., active records only) |
| Unique? | If data should be unique, enforce with UNIQUE for integrity + performance |
Let's examine common database scenarios and the recommended indexing strategies for each.
Scenario: High-Volume Transaction Processing
Characteristics:
Recommended Strategy:
-- Clustered on auto-increment for insert speed
CREATE TABLE Orders (
OrderID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
CustomerID INT NOT NULL,
OrderDate DATETIME NOT NULL,
Status VARCHAR(20) NOT NULL,
TotalAmount DECIMAL(18,2)
);
-- Minimal non-clustered for critical lookups
CREATE NONCLUSTERED INDEX IX_Orders_CustomerID
ON Orders(CustomerID) INCLUDE (OrderDate, TotalAmount);
-- Foreign key index for join performance
CREATE NONCLUSTERED INDEX IX_Orders_Status
ON Orders(Status) WHERE Status = 'Pending';
Rationale:
Every indexing decision involves trade-offs. This matrix helps you systematically evaluate options.
Storage vs Performance Trade-offs:
| Choice | Storage Cost | Read Performance | Write Performance |
|---|---|---|---|
| Heap (no clustered) | Minimal overhead | Poor (no ordering) | Good (no order maintenance) |
| Clustered only | Base storage | Excellent for key ranges | Good (one index maintained) |
| Clustered + 1-2 NC | Moderate (+10-20%) | Very good (multiple paths) | Good (limited overhead) |
| Clustered + 5+ NC | Significant (+50%+) | Excellent (many paths) | Poor (high maintenance) |
| Covering NC indexes | High (duplicate columns) | Excellent (no lookups) | Poor (wide index maintenance) |
| Indexed views | Very high (data copy) | Excellent (dedicated) | Very poor (view maintenance) |
Key Width Trade-offs:
| Key Width | Fanout | Tree Height | NC Index Impact | Best For |
|---|---|---|---|---|
| 4 bytes (INT) | ~500 entries/page | 2-3 levels | Minimal | Most OLTP tables |
| 8 bytes (BIGINT) | ~400 entries/page | 2-3 levels | Low | Large tables, millisecond timestamps |
| 16 bytes (GUID) | ~300 entries/page | 3-4 levels | Moderate | Distributed systems (use UUIDv7) |
| 50+ bytes (composite) | ~100 entries/page | 4-5 levels | High | Only if query patterns demand |
When making indexing decisions, quantify the trade-offs. Calculate expected storage sizes, estimate write overhead percentages, and measure actual query improvements. Decisions based on measurement outperform decisions based on intuition.
Feature vs Maintenance Trade-offs:
| Feature | Benefit | Maintenance Cost |
|---|---|---|
| INCLUDE columns | Eliminates lookups | Updated on any included column change |
| Filtered indexes | Smaller, focused | Requires careful predicate design |
| Computed columns | Index expressions | Column maintenance on source changes |
| Unique constraints | Data integrity | Validation on every insert/update |
| Partitioning | Isolation, aging | Partition management complexity |
Indexes aren't 'set and forget.' Effective index management requires ongoing monitoring, evaluation, and adjustment.
The Index Lifecycle:
Key Monitoring Metrics:
123456789101112131415161718192021222324252627282930
-- SQL Server: Find unused indexesSELECT i.name AS IndexName, OBJECT_NAME(i.object_id) AS TableName, ius.user_seeks, ius.user_scans, ius.user_lookups, ius.user_updatesFROM sys.indexes iJOIN sys.dm_db_index_usage_stats ius ON i.object_id = ius.object_id AND i.index_id = ius.index_idWHERE ius.database_id = DB_ID() AND (ius.user_seeks + ius.user_scans + ius.user_lookups) < ius.user_updatesORDER BY (ius.user_updates - ius.user_seeks - ius.user_scans - ius.user_lookups) DESC; -- SQL Server: Find missing indexesSELECT mig.index_group_handle, mid.statement AS TableName, mid.equality_columns, mid.inequality_columns, mid.included_columns, migs.user_seeks, migs.avg_user_impactFROM sys.dm_db_missing_index_groups migJOIN sys.dm_db_missing_index_group_stats migs ON mig.index_group_handle = migs.group_handleJOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handleORDER BY migs.avg_user_impact * migs.user_seeks DESC;If an index has zero seeks and zero scans over several weeks (across all typical workload periods), it's likely a candidate for removal. But verify: some indexes may be used only monthly (e.g., month-end reports). Capture usage over a full business cycle before dropping.
Years of database consulting reveal recurring indexing mistakes. Understanding these helps you avoid the same pitfalls.
The Consolidation Principle:
Instead of creating separate indexes for each query:
-- DON'T: Separate indexes
CREATE INDEX IX1 ON Orders(CustomerID);
CREATE INDEX IX2 ON Orders(CustomerID, OrderDate);
CREATE INDEX IX3 ON Orders(CustomerID) INCLUDE (TotalAmount);
-- DO: Consolidated covering index
CREATE INDEX IX_Orders_Customer ON Orders(CustomerID, OrderDate)
INCLUDE (TotalAmount, Status);
The consolidated index:
Always test index changes with realistic data volumes. An index that seems to help on 10,000 rows may behave differently on 10 million rows. Use Query Store, execution plan comparisons, and A/B testing to validate improvements before production deployment.
We've synthesized the theoretical foundation of clustered and non-clustered indexes into practical selection criteria. Here's the complete framework:
The Master Decision Tree:
Need to optimize table access?
│
├─ Identify the MOST CRITICAL range query pattern
│ └─ Cluster the table on that pattern's key
│
├─ Identify OTHER frequent query patterns
│ ├─ High selectivity? → Non-clustered index
│ ├─ Need all columns? → Add INCLUDE
│ └─ Partial data (e.g., Status='Active')? → Filtered index
│
├─ Monitor after deployment
│ ├─ Unused indexes → Drop them
│ ├─ Missing index suggestions → Evaluate and consolidate
│ └─ High fragmentation → Maintain regularly
│
└─ Repeat as workload evolves
Congratulations! You've completed an exhaustive study of clustered vs non-clustered indexes. You understand their structures, mechanics, the physical ordering constraint, and practical selection criteria. You're now equipped to design optimal indexing strategies for any database workload — a core competency of expert database professionals.