skip to content

Compare a partition-local index with an Oracle-style global index on the same partitioned table: what does each buy you at query time, and what does each cost you when partitions are dropped or exchanged?

level: middleimportance: must knowfreq 48%

answer

  1. local = aligned, one per partition
  2. global = spans all partitions, Oracle/SQL Server only
  3. global unique ⇒ no partition key needed in the key
  4. DROP PARTITION ⇒ global index UNUSABLE unless UPDATE INDEXES
  5. global = single hot tree, all-or-nothing rebuild

basics

~20 s

A local index is one index per partition: cheap partition lifecycle, per-partition rebuilds, but N probes when the query cannot be pruned, and uniqueness only within a partition. A global index is one index over all partitions: single-probe lookups and true global uniqueness, but dropping or exchanging a partition invalidates it and forces maintenance.

solid answer

~60 s

**Local (aligned) index** — one physical index per partition, keyed the same way the table is partitioned. - Query: great when the predicate prunes to one or a few partitions; poor for a non-partition-key lookup, which must probe every partition. - Maintenance: partition drop/truncate/exchange is metadata-only. Builds and rebuilds are per partition, parallelisable, resumable. - Uniqueness: only within a partition, so unique keys must contain the partition key. **Global index** — one index (possibly partitioned on a different key) spanning the whole table. - Query: one probe for a non-partition-key lookup; supports global uniqueness and efficient ordered scans across partitions. - Maintenance: any partition-level DDL either invalidates the index or forces row-by-row maintenance — in Oracle, `DROP PARTITION` without `UPDATE INDEXES` marks it UNUSABLE. It also becomes a single large, contended, bloat-prone structure and a rebuild bottleneck. So the rule of thumb: partition to get cheap retention and pruning, and use local indexes; reach for a global index only when a critical non-partition-key access path or global uniqueness genuinely requires it, and accept the maintenance tax. PostgreSQL and MySQL don't offer the choice — local only.

code

sql · 6 lines
sql
CREATE INDEX orders_cust_local ON orders (customer_id) LOCAL;

CREATE UNIQUE INDEX orders_pk_global ON orders (order_id) GLOBAL;

-- without UPDATE INDEXES this marks orders_pk_global UNUSABLE
ALTER TABLE orders DROP PARTITION orders_2024_01 UPDATE INDEXES;

go deeper

for a junior

Know the two words and the one-line difference: local = per partition, global = one index over all partitions.

for a middle

Be able to state both tradeoffs — query fan-out vs partition-lifecycle cost — and that only some engines offer global indexes.

for a senior

Tie the choice to operations: what DROP PARTITION does to a global index, rebuild windows, and how you'd preserve a critical access path in an engine that has only local indexes.

for a principal

Present it as a coupling decision: partitioning buys independence between slices of data, and a global index spends that independence to buy back a global access path — decide which property the system's SLOs actually need.

## Definitions **Local index** (Oracle `LOCAL`; SQL Server calls the concept an *aligned* index; the only option in PostgreSQL and MySQL): the index is partitioned exactly the way the table is. Partition *i* of the table has its own index containing only partition *i*'s rows. There is a one-to-one correspondence between table partitions and index partitions. **Global index** (Oracle `GLOBAL`; SQL Server *nonaligned*): the index is a structure over the whole table, independent of how the table is partitioned. It may itself be non-partitioned, or partitioned on a *different* key — for example, the table ranged by `order_date` while a global index on `customer_id` is hash-partitioned by `customer_id`. ## Query-time behaviour The question is always: can the engine restrict the search to a few partitions? - Predicate includes the partition key → the planner prunes, and a local index is ideal: a small, shallow tree with high cache residency. - Predicate omits the partition key → a local index means one probe per surviving partition plus an append/merge. With 200 partitions, a 5-microsecond point lookup becomes a millisecond of work, and any `ORDER BY ... LIMIT` may need rows gathered from all partitions before it can answer. A global index answers the same query with a single probe, exactly as if the table were not partitioned. So global indexes exist mainly to preserve OLTP access paths on columns unrelated to the partition key: `SELECT * FROM orders WHERE order_id = ?` on a table partitioned by month. ## Constraint behaviour A unique local index enforces uniqueness only inside each partition; two identical values in different partitions both succeed. Therefore engines with only local indexes require every partition-key column to be part of any `PRIMARY KEY`/`UNIQUE` constraint. A **global unique index** removes that restriction: Oracle can enforce `UNIQUE (order_id)` on a table partitioned by `order_date`, because one structure sees every row. This is frequently the actual reason a team wants global indexes. ## Maintenance-time behaviour — the real cost Partitioning is usually adopted for cheap data lifecycle: `DROP PARTITION` deletes a month of data in milliseconds because it is a metadata operation on a separate physical object. Local indexes preserve that: the partition's index segments are dropped with it. A global index breaks the isolation. Its entries point at rows in the partition you just dropped, so the engine must either: 1. Mark the index **UNUSABLE** (Oracle's default for `DROP`/`TRUNCATE`/`EXCHANGE PARTITION` without `UPDATE INDEXES` / `UPDATE GLOBAL INDEXES`), leaving every query that depended on it to fall back to full scans until you rebuild — a full rebuild of a multi-hundred-GB index; or 2. Maintain it inline (`UPDATE INDEXES`), which turns an O(1) metadata drop into work proportional to the number of rows removed, holding locks and generating redo for the duration. Oracle mitigates this with **asynchronous global index maintenance**: the drop returns quickly and the orphaned entries are cleaned up later by a maintenance job, but the index carries dead entries in the meantime and cleanup still has to run. Other costs of a global index: - **Single hot structure.** All partitions' inserts hit one tree; with monotonically increasing keys, the right-hand leaf becomes a contention point. - **Build/rebuild is all-or-nothing.** You cannot rebuild it a slice at a time or skip cold data; a rebuild is one long, large operation. - **No selective indexing.** You cannot index only the hot partitions. - **Attach/exchange friction.** Swapping a prepared table into the partitioned table is instant with local indexes and requires global-index maintenance otherwise. ## Choosing A workable decision procedure: 1. Pick the partition key from the dominant access pattern *and* the retention requirement. 2. Default all indexes to local. 3. List the access paths that will now be unprunable. Estimate their cost as (partition count × probe cost) at the partition count you'll have in two years — not today's count. 4. If one of those paths is latency-critical or a uniqueness rule cannot include the partition key, and your engine supports it, add a *global* index for exactly that path and change your partition-lifecycle scripts to maintain it (`UPDATE INDEXES`, or rebuild windows). 5. If your engine has no global indexes, the alternatives are: repartition on the key that matters, keep a small non-partitioned lookup/registry table mapping the alternate key to the partition key, or accept the fan-out. ## One-line summary Local indexes make partitions independent; global indexes make the table look unpartitioned again. You pay for whichever property you didn't choose.

  • PostgreSQL has no global indexes. How do teams get a fast lookup on a non-partition-key column there?
    Options are: make the predicate prunable by including the partition key in the query (often by carrying it on the referencing rows), accept the fan-out when partition count is small and probes are cheap, keep a compact non-partitioned side table mapping the alternate key to the partition key and then do a two-step lookup, or move that access path out of the partitioned table entirely. Choosing a partition key that matches the hot OLTP predicate up front avoids the problem altogether.
  • When is a global index clearly the right call despite the maintenance cost?
    When the table is partitioned for a reason unrelated to its hottest lookup — for example partitioned by date for retention while the OLTP path is a point lookup by primary key — and when partition-level DDL is rare or scheduled. It is also the answer when a business rule demands uniqueness on a natural key that cannot include the partition key. The price is that every drop/exchange must run with index maintenance or be followed by a rebuild window.

saying these in an interview costs you the question

  • Claiming global indexes are strictly better because they avoid fan-out — they re-couple partitions and break cheap drops.
  • Not knowing that dropping a partition can leave a global index UNUSABLE.
  • Thinking PostgreSQL or MySQL can create a cross-partition (global) index.
  • Assuming a local index can enforce uniqueness across the whole table.
  • Evaluating fan-out cost at today's partition count instead of the count after a few years of retention.

context