Clustered vs Non-Clustered Indexes
Physical Ordering
Read aloud is unavailable in this browser.
The Difference Between What You See and How It's Stored
When you query a database with SELECT * FROM Customers ORDER BY LastName, you receive rows sorted alphabetically by last name. But how are those rows actually stored on disk? Are they physically arranged in alphabetical order, or is the database performing sorting on the fly?
The answer depends entirely on the table's physical ordering—whether and how a clustered index defines the storage layout. This distinction between logical order (how data appears in query results) and physical order (how data resides on storage media) is fundamental to understanding database performance.
Physical ordering determines whether range queries blaze through sequential disk blocks or crawl through random I/O. It influences whether inserts are fast appends or expensive mid-table insertions. It affects how fragmentation develops and how maintenance operations behave. Every aspect of storage-level performance traces back to physical ordering decisions.
By the end of this page, you will understand the critical distinction between logical and physical ordering, how clustered indexes impose physical structure, the performance implications of sequential vs random access patterns, and how physical ordering decisions propagate through every operation your database performs.
Logical vs Physical Order
Understanding the difference between logical and physical ordering is the foundation for comprehending index behavior and storage performance.
Logical Order:
Logical order is the conceptual arrangement of data as you think about it or as queries present it:
- How rows relate to each other in your mental model
- The sort order specified in ORDER BY clauses
- The sequence implied by primary key values
- The organization apparent in query results
Logical order exists in your data model and query specifications. It's abstract—independent of how bytes are actually arranged on disk.
Physical Order:
Physical order is the actual arrangement of data bytes on storage media:
- Which rows are stored in which disk sectors
- The sequence of pages in database files
- Adjacent storage locations for related data
- The layout that determines I/O patterns
Physical order is concrete—it directly determines how disk heads move, which SSD cells are accessed, and whether reads are sequential or random.
| Aspect | Logical Order | Physical Order |
|---|---|---|
| Nature | Conceptual, abstract | Concrete, measurable |
| Defined by | Primary keys, indexes, queries | Clustered index, storage engine |
| Visibility | Query results, application code | Execution plans, I/O statistics |
| Impact | Correctness, semantics | Performance, resource usage |
| Modification | Schema design, query writing | Index creation, rebuilds, storage config |
| Persistence | Database schema, constraints | File layout, page allocation |
The relational model intentionally hides physical ordering. Tables are defined as unordered sets of tuples—there is no 'first row' or 'last row' conceptually. Query results have order only when ORDER BY is specified. This abstraction grants DBMSs flexibility in physical organization, enabling optimizations without breaking applications.
The Bridge: Clustered Indexes
Clustered indexes are the mechanism that connects logical and physical order:
- When you create a clustered index on a column, you're declaring that the physical storage order should match the logical order of that column's values
- The database engine physically rearranges data pages so that rows are stored in clustered key order
- Range queries on the clustered key access physically contiguous pages
- The logical order defined by the clustered key becomes the physical reality
Without a clustered index:
- Data is stored in a heap—insertion order or wherever space is available
- No correlation between any logical ordering and physical storage
- All index-based access patterns result in random I/O
- Full scans read pages in physical order, which is essentially arbitrary
How Clustered Indexes Impose Physical Order
When a clustered index is created, the database engine performs a series of operations to establish and maintain physical ordering:
Initial Creation:
- •Sort Data: All existing rows are sorted according to the clustered key values
- •Allocate Pages: Contiguous data pages are allocated to hold sorted rows
- •Write Sequentially: Rows are written to pages in sorted order, filling each page before moving to the next
- •Build Index Levels: Internal B+ tree pages are created above the data pages for navigation
- •Link Pages: Leaf (data) pages are linked in a doubly-linked list for range scans
- •Update Metadata: System catalogs are updated to reflect the new storage structure
Physical Layout After Creation:
Consider a table Orders with a clustered index on OrderDate. After index creation:
Physical Disk Layout:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Page 101 │──▶│ Page 102 │──▶│ Page 103 │──▶│ Page 104 │
│ Jan 1-Jan 5 │ │ Jan 6-Jan 10│ │ Jan 11-Jan 15│ │ Jan 16-Jan 20│
│ Orders │ │ Orders │ │ Orders │ │ Orders │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│ │ │ │
└─────────────────┴─────────────────┴─────────────────┘
Physically Contiguous on Disk
Queries for WHERE OrderDate BETWEEN 'Jan 6' AND 'Jan 15' read pages 102 and 103 sequentially—they're adjacent on disk.
Maintenance of Physical Order:
After creation, the database attempts to maintain physical order as data changes:
- Sequential Inserts: New rows at the 'end' of the key range append to the last data pages
- Mid-Range Inserts: New rows in the middle may require page splits to maintain order
- Updates: Row growth may cause movement; key changes cause delete + insert
- Deletes: Create gaps that may be reused or cause fragmentation
Physical order is not perfectly maintained over time. Page splits allocate new pages that may not be physically adjacent. Fragmentation develops. Eventually, 'page 102' might be followed logically by 'page 847' on a different disk region. Regular maintenance (rebuild, reorganize) restores physical contiguity.
Sequential vs Random I/O: The Performance Multiplier
The performance difference between sequential and random I/O is the fundamental reason physical ordering matters. Understanding this difference at the hardware level explains why clustered indexes are so powerful.
Hard Disk Drives (HDDs):
Traditional spinning disks have mechanical components that create stark performance differences:
-
Sequential Read: ~100-200 MB/s
- Disk head stays on track
- Continuous data stream
- Minimal seek time
-
Random Read: ~0.5-2 MB/s for small blocks
- Each read requires head seek (3-10ms)
- Rotational latency (2-8ms)
- Can only sustain 100-300 IOPS
The Ratio: Sequential is 50-200x faster than random on HDDs
| Storage Type | Sequential Throughput | Random IOPS | Random Latency | Seq/Random Ratio |
|---|---|---|---|---|
| 7200 RPM HDD | 150 MB/s | 150 IOPS | ~10ms | ~100x |
| 15000 RPM HDD | 200 MB/s | 300 IOPS | ~5ms | ~80x |
| SATA SSD | 500 MB/s | 50,000 IOPS | ~0.1ms | ~5-10x |
| NVMe SSD | 3,500 MB/s | 500,000 IOPS | ~0.02ms | ~2-5x |
| Intel Optane | 2,500 MB/s | 550,000 IOPS | ~0.01ms | ~2x |
Solid State Drives (SSDs):
SSDs have no mechanical components, but sequential vs random still matters:
- No Seek Time: Random access doesn't require physical movement
- But Still Different: Prefetching, block alignment, wear leveling favor sequential
- Parallelism: SSDs can parallelize sequential reads across channels
- Write Amplification: Random writes require more internal operations
The Ratio: Sequential is 2-10x faster on SSDs, depending on operations
Why This Matters for Databases:
- •Range Queries: Clustered index range scans read contiguous pages—pure sequential I/O
- •Prefetching: OS and disk controllers can read ahead, anticipating next requests
- •Buffer Pool Efficiency: Contiguous data loads efficiently into memory
- •Write Batching: Sequential data layouts enable efficient write coalescing
- •Scan Operations: Full table scans on clustered data stream at maximum throughput
While SSDs reduce the penalty of random I/O dramatically, sequential access remains faster. More importantly, enterprise databases often process millions of operations per second. A 5x difference at scale translates to massive performance and cost implications. Physical ordering remains critical even in all-flash environments.
Physical Order and Query Operations
Let's examine how physical ordering impacts specific query operations, demonstrating why the clustered index choice is critical.
Range Queries:
Consider SELECT * FROM Sales WHERE SaleDate BETWEEN '2024-01-01' AND '2024-01-31'
- •Navigate B+ tree to first matching date
- •Scan leaf pages sequentially
- •Each page contains 100+ adjacent date rows
- •~10 pages for 1,000 rows
- •~10 sequential I/Os
- •Use non-clustered index on SaleDate
- •Find all matching entries
- •Each entry requires bookmark lookup
- •Rows scattered across all data pages
- •~1,000 random I/Os for 1,000 rows
ORDER BY Operations:
When query results must be sorted by a specific column:
- If ORDER BY matches clustered key: Results are already in order—no sort needed
- If ORDER BY differs from clustered key: Database must sort results, using memory or temporary disk space
For queries like SELECT * FROM Orders ORDER BY CustomerID, OrderDate:
- Clustered on (CustomerID, OrderDate): Free—data emerges in order
- Clustered on OrderID: Requires expensive sort operation
GROUP BY and Aggregation:
Aggregation queries benefit from physical ordering:
SELECT CustomerID, SUM(Amount), COUNT(*)
FROM Orders
GROUP BY CustomerID
- Clustered on CustomerID: All rows for each customer are contiguous; aggregate as you scan
- Clustered on OrderDate: Rows for each customer scattered; requires hash aggregation or sort
Sort operations are expensive—they consume memory, may spill to disk, and block pipeline execution. Aligning clustered index keys with common ORDER BY and GROUP BY patterns eliminates these costs entirely. Examine your most frequent queries' sort requirements when choosing a clustered key.
Join Operations:
Join algorithms also benefit from physical ordering:
Merge Join: Requires both inputs sorted on join keys
- If both tables are clustered on join keys: Merge join is optimal
- If not: Sort operations required before merging
Nested Loop Join with Range Predicates:
- Outer table clustered on join column: Efficient range access
- Random access to outer table: More I/O per lookup
Index Intersection/Union:
- Multiple non-clustered index results must be merged
- Physical ordering of base table affects final data retrieval
Heap Storage: The Absence of Physical Order
A heap is a table without a clustered index—data is stored without any particular order. Understanding heap behavior illuminates why physical ordering matters.
Heap Characteristics:
- •No Defined Order: Rows are stored wherever space is available
- •Insertion Order (Initially): New rows typically go to the last page with space or a new page
- •Space Reuse: Deleted row space may be reused for future inserts
- •No Leaf Links: Pages are not linked in any logical sequence
- •IAM Pages: Index Allocation Maps track which pages belong to the table
Full Scan Behavior:
When scanning a heap (no WHERE clause or non-selective filter):
- The engine reads all pages belonging to the table
- Page order is physical allocation order, not related to data content
- Sequential I/O is possible if pages are allocated contiguously
- But no logical ordering—results appear in arbitrary order
Index Access to Heaps:
Non-clustered indexes on heaps use physical Row IDs (RIDs) as locators:
RID = (FileID : PageID : SlotNumber)
Example: 1:4523:7 = File 1, Page 4523, Slot 7
This enables direct page access without tree traversal, but:
- Row movement (from UPDATE) creates forwarding pointers
- Forwarding chains develop: RID → Forwarding → Forwarding → Data
- Performance degrades as chains lengthen
In heavily updated heaps, forwarding chains can extend to 10+ levels. Each lookup requires following the entire chain. This is why heaps are generally discouraged for tables with variable-length columns that frequently grow. A clustered index (even on an identity column) eliminates this problem entirely.
When Heaps Are Appropriate:
Despite their limitations, heaps serve specific use cases:
- Staging Tables: Bulk load data, then process or transform—no need for ordering
- Insert-Only Logging: Append-only write patterns with periodic bulk deletes
- Full-Scan Only Access: Tables always scanned completely, never queried by key
- Temporary Tables: Short-lived tables where maintenance overhead outweighs benefits
- Very Small Tables: Lookup tables with few rows—physical order irrelevant
For production tables with selective queries, range scans, or update patterns, a clustered index is almost always preferable.
Fragmentation and Physical Order Decay
Physical ordering established by a clustered index degrades over time through a process called fragmentation. Understanding fragmentation types and their causes helps you maintain optimal physical organization.
Types of Fragmentation:
Logical (External) Fragmentation:
The logical order of pages (by clustered key) differs from their physical order on disk.
Cause: Page splits allocate new pages from available disk space, which may not be adjacent to existing pages.
Effect: Sequential scans by clustered key become random I/O as the disk head jumps between scattered pages.
Measurement:
-- SQL Server
SELECT avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(
DB_ID(), OBJECT_ID('Orders'), 1, NULL, 'LIMITED'
);
-- Values:
-- < 10%: Generally acceptable
-- 10-30%: Consider REORGANIZE
-- > 30%: Consider REBUILD
Example: Pages in logical order 1→2→3→4 might be physically stored as 1→7→2→15, requiring three random seeks for what should be sequential access.
Fragmentation Prevention Strategies:
- •Sequential Keys: Use auto-increment or sequential values for clustered keys; new rows append, minimizing mid-table splits
- •Appropriate Fill Factor: Set 70-90% fill factor for update-heavy tables; leaves room for growth
- •Regular Maintenance: Schedule REBUILD or REORGANIZE during maintenance windows; frequency depends on write patterns
- •Monitor Continuously: Track fragmentation levels; alert when thresholds exceeded
- •Avoid Random Keys: UUIDs and random values as clustered keys guarantee fragmentation
Physical Order Across Database Systems
Different database systems handle physical ordering with varying approaches and terminology. Understanding these differences is essential when working across platforms.
| DBMS | Clustered Index Support | Default Table Type | Key Points |
|---|---|---|---|
| SQL Server | Full support; optional per table | Heap (unless PK defined) | PK is clustered by default; explicit control available |
| MySQL/InnoDB | Mandatory; always has clustered index | Index-Organized Table | Every table clustered on PK; cannot opt out |
| PostgreSQL | No persistent clustered index | Heap with indexes | CLUSTER command reorders once; not maintained |
| Oracle | Index-Organized Tables (IOT) optional | Heap by default | IOTs are explicitly requested; less common |
| SQLite | WITHOUT ROWID tables | Rowid-based heap | WITHOUT ROWID creates clustered-like behavior |
PostgreSQL's CLUSTER Command:
PostgreSQL lacks true clustered indexes but provides the CLUSTER command:
-- Reorder table data according to an index
CLUSTER Orders USING idx_orders_date;
-- Recluster all previously clustered tables
CLUSTER;
Important Caveats:
- CLUSTER is a one-time operation; does not maintain order
- Requires exclusive table lock; blocks all access
- Subsequent inserts go wherever space exists
- Must re-cluster periodically via scheduled job
- Not a true clustered index—no ongoing maintenance
InnoDB's Mandatory Clustering:
MySQL's InnoDB always maintains a clustered index:
- If PRIMARY KEY exists → clustered on PK
- Else if UNIQUE NOT NULL index exists → clustered on first such index
- Else → hidden 6-byte row ID as clustered key
Implication: You cannot have a 'heap' table in InnoDB. Every table has physical ordering based on some key. Secondary indexes store the clustered key, not RIDs, adding overhead if the clustered key is large.
When designing for PostgreSQL, consider tables as inherently unordered heaps with very good index support. For InnoDB, every table design is implicitly a clustered index design—choose your primary key as if choosing a clustered key. For SQL Server/Oracle, you have explicit choice and should use it deliberately.
KEEP LEARNING
There’s more to understand.
You’re reading the introduction. Create a free account to read the complete lesson, save notes and keep track of your progress.