Skip to content
About
Main content

Clustered versus non-clustered: the only lever on pages touched

Why do you get only one clustered index?

the crossover from Why indexes exist: the index wins when k/N < s/r, where k counts pages, not rows. Clustering is the only mechanism that reduces pages without reducing rows.

Let f be rows per page. A range query returning k rows costs:

rows the range query returns
rows per page, typically 20 to 200
rows in the table
clustered (sequential)unclustered (random)
Data table
Pages read by rows returned (10⁸ rows, 100 per page)
Rows returned kseriesPages read
100clustered (sequential)1
119clustered (sequential)1.19
141clustered (sequential)1.41
168clustered (sequential)1.68
200clustered (sequential)2
237clustered (sequential)2.37
282clustered (sequential)2.82
335clustered (sequential)3.35
398clustered (sequential)3.98
473clustered (sequential)4.73
562clustered (sequential)5.62
668clustered (sequential)6.68
794clustered (sequential)7.94
944clustered (sequential)9.44
1.12Kclustered (sequential)11.2
1.33Kclustered (sequential)13.3
1.58Kclustered (sequential)15.8
1.88Kclustered (sequential)18.8
2.24Kclustered (sequential)22.4
2.66Kclustered (sequential)26.6
3.16Kclustered (sequential)31.6
3.76Kclustered (sequential)37.6
4.47Kclustered (sequential)44.7
5.31Kclustered (sequential)53.1
6.31Kclustered (sequential)63.1
7.5Kclustered (sequential)75
8.91Kclustered (sequential)89.1
10.6Kclustered (sequential)106
12.6Kclustered (sequential)126
15Kclustered (sequential)150
17.8Kclustered (sequential)178
21.1Kclustered (sequential)211
25.1Kclustered (sequential)251
29.9Kclustered (sequential)299
35.5Kclustered (sequential)355
42.2Kclustered (sequential)422
50.1Kclustered (sequential)501
59.6Kclustered (sequential)596
70.8Kclustered (sequential)708
84.1Kclustered (sequential)841
100Kclustered (sequential)1K
119Kclustered (sequential)1.19K
141Kclustered (sequential)1.41K
168Kclustered (sequential)1.68K
200Kclustered (sequential)2K
237Kclustered (sequential)2.37K
282Kclustered (sequential)2.82K
335Kclustered (sequential)3.35K
398Kclustered (sequential)3.98K
473Kclustered (sequential)4.73K
562Kclustered (sequential)5.62K
668Kclustered (sequential)6.68K
794Kclustered (sequential)7.94K
944Kclustered (sequential)9.44K
1.12Mclustered (sequential)11.2K
1.33Mclustered (sequential)13.3K
1.58Mclustered (sequential)15.8K
1.88Mclustered (sequential)18.8K
2.24Mclustered (sequential)22.4K
2.66Mclustered (sequential)26.6K
3.16Mclustered (sequential)31.6K
3.76Mclustered (sequential)37.6K
4.47Mclustered (sequential)44.7K
5.31Mclustered (sequential)53.1K
6.31Mclustered (sequential)63.1K
7.5Mclustered (sequential)75K
8.91Mclustered (sequential)89.1K
10.6Mclustered (sequential)106K
12.6Mclustered (sequential)126K
15Mclustered (sequential)150K
17.8Mclustered (sequential)178K
21.1Mclustered (sequential)211K
25.1Mclustered (sequential)251K
29.9Mclustered (sequential)299K
35.5Mclustered (sequential)355K
42.2Mclustered (sequential)422K
50.1Mclustered (sequential)501K
59.6Mclustered (sequential)596K
70.8Mclustered (sequential)708K
84.1Mclustered (sequential)841K
100Mclustered (sequential)1M
100unclustered (random)100
119unclustered (random)119
141unclustered (random)141
168unclustered (random)168
200unclustered (random)200
237unclustered (random)237
282unclustered (random)282
335unclustered (random)335
398unclustered (random)398
473unclustered (random)473
562unclustered (random)562
668unclustered (random)668
794unclustered (random)794
944unclustered (random)944
1.12Kunclustered (random)1.12K
1.33Kunclustered (random)1.33K
1.58Kunclustered (random)1.58K
1.88Kunclustered (random)1.88K
2.24Kunclustered (random)2.24K
2.66Kunclustered (random)2.66K
3.16Kunclustered (random)3.16K
3.76Kunclustered (random)3.76K
4.47Kunclustered (random)4.47K
5.31Kunclustered (random)5.31K
6.31Kunclustered (random)6.31K
7.5Kunclustered (random)7.5K
8.91Kunclustered (random)8.91K
10.6Kunclustered (random)10.6K
12.6Kunclustered (random)12.6K
15Kunclustered (random)15K
17.8Kunclustered (random)17.8K
21.1Kunclustered (random)21.1K
25.1Kunclustered (random)25.1K
29.9Kunclustered (random)29.9K
35.5Kunclustered (random)35.5K
42.2Kunclustered (random)42.2K
50.1Kunclustered (random)50.1K
59.6Kunclustered (random)59.6K
70.8Kunclustered (random)70.8K
84.1Kunclustered (random)84.1K
100Kunclustered (random)100K
119Kunclustered (random)119K
141Kunclustered (random)141K
168Kunclustered (random)168K
200Kunclustered (random)200K
237Kunclustered (random)237K
282Kunclustered (random)282K
335Kunclustered (random)335K
398Kunclustered (random)398K
473Kunclustered (random)473K
562Kunclustered (random)562K
668Kunclustered (random)668K
794Kunclustered (random)794K
944Kunclustered (random)944K
1.12Munclustered (random)1M
1.33Munclustered (random)1M
1.58Munclustered (random)1M
1.88Munclustered (random)1M
2.24Munclustered (random)1M
2.66Munclustered (random)1M
3.16Munclustered (random)1M
3.76Munclustered (random)1M
4.47Munclustered (random)1M
5.31Munclustered (random)1M
6.31Munclustered (random)1M
7.5Munclustered (random)1M
8.91Munclustered (random)1M
10.6Munclustered (random)1M
12.6Munclustered (random)1M
15Munclustered (random)1M
17.8Munclustered (random)1M
21.1Munclustered (random)1M
25.1Munclustered (random)1M
29.9Munclustered (random)1M
35.5Munclustered (random)1M
42.2Munclustered (random)1M
50.1Munclustered (random)1M
59.6Munclustered (random)1M
70.8Munclustered (random)1M
84.1Munclustered (random)1M
100Munclustered (random)1M

So clustering buys up to an f-fold reduction in I/O, and f is typically 20 to 200 for a row store on 8 KB pages.

Substitute this into the crossover and the "5% rule" dissolves into two rules:

  • An unclustered index stops helping at low single-digit (here 0.25% to 1%).
  • A clustered index on a range predicate essentially never loses to a scan, because it is the scan, started in the right place.

This is the highest-leverage number in this article. Almost every "why isn't my index being used" question is this arithmetic.

There is only one clustered order per table, because the is the layout. Indexing dropped the single-order limitation for secondary access and relocated it onto one privileged index.

Heap-organized versus index-organized tables is a genuine engineering choice, not a settled question. For this mechanism we only need its consequence for index references (physical or logical pointer). In outline:

(PostgreSQL, Oracle by default)Index-organized (InnoDB, Oracle IOTs, SQL Server clustered tables)
cheapeach pays the double descent
Updatescheapwide PK taxes everything
PK ordernot forcedforced
Clusteringno guaranteeguaranteed by PK
PK range scansnormalfast; no separate heap

In PostgreSQL, CLUSTER is a one-time physical reorder that decays with every later write. The 's correlation statistic is literally a measurement of how far it has decayed.

In column stores the same mechanism returns under other names (sort keys, Z-order, liquid clustering), and the skipping is done by rather than a tree (sparse indexes and zone maps). Same constraint, same scarcity, different organ.