Understanding Z-Ordering
Almost every optimization in analytical data platforms exists to answer one question:
How can we avoid reading unnecessary data?
The less data a query reads from storage, the faster it runs.
Storage vs Data Layout
Storage
Storage answers:
Where do the bytes live?
Examples:
- Amazon S3
- Azure Data Lake Storage
- Google Cloud Storage
- HDFS
- SSDs
Storage is concerned with:
- durability
- availability
- throughput
- latency
- cost
Storage does not understand SQL queries or business meaning.
It simply stores bytes.
Example:
sales/
part-00001.parquetpart-00002.parquetpart-00003.parquetData Layout
Data layout answers:
How are those bytes organized?
The same storage system can contain different layouts.
The storage is identical, but the organization is different.
Random Layout
File 1
Customer 45Customer 9000Customer 12Customer 700000The file contains a wide range of values.
Metadata:
min = 12max = 700000This is not very useful for skipping.
Optimized Layout
File 1
Customer 1-10000
File 2
Customer 10001-20000Metadata:
File 1
min = 1max = 10000
File 2
min = 10001max = 20000Now the engine can eliminate files quickly.
The storage did not change.
The layout changed.
Why Data Layout Matters
Modern analytical systems use columnar formats such as Parquet.
Every Parquet file contains statistics.
Example:
File A
CustomerID
min = 1max = 10000
File B
CustomerID
min = 10001max = 20000Query:
SELECT *FROM salesWHERE customer_id = 15000;The engine performs data skipping:
File A -> SkipFile B -> ReadFile C -> SkipFile D -> SkipThe query becomes faster because unnecessary files are never opened.
Partitioning
Partitioning is a layout strategy that organizes files into directories.
Example:
sales/
βββ year=2024/ββ part-001.parquetββββ year=2025/
part-001.parquetQuery:
SELECT *FROM salesWHERE year = 2025;The engine only considers:
year=2025/The 2024 data is ignored.
This is called:
Partition pruning
When to Partition
Good partition columns:
- year
- month
- country
- region
Poor partition columns:
- customer_id
- transaction_id
- user_id
Why?
Because high-cardinality columns create too many small partitions.
Example:
customer_id=1/customer_id=2/customer_id=3/...customer_id=500000000/This creates a partition explosion.
Indexes
Traditional databases solve query lookup differently.
They create an additional data structure.
Example:
INDEX
CustomerID
100 -------------> Row 10
101 -------------> Row 22
102 -------------> Row 45
TABLE
Actual DataThe table itself does not change.
The index provides a shortcut.
A B-tree index is like the index at the back of a textbook.
The textbook remains unchanged.
The index tells you where to go.
Why Data Lakes Usually Do Not Use Traditional Indexes
Traditional databases are optimized for:
- many small queries
- frequent updates
- point lookups
Example:
SELECT *FROM customersWHERE customer_id = 12345;Analytical data platforms are different.
They handle:
- billions of rows
- large scans
- batch processing
- mostly immutable data
Maintaining indexes at petabyte scale becomes expensive.
Instead, systems like Delta Lake rely on:
- partition pruning
- Parquet statistics
- predicate pushdown
- data skipping
- optimized file layout
Z-Ordering
Z-ordering comes from the Morton order, a mathematical technique for organizing multidimensional data.
The problem:
Imagine queries filtering on:
customer_id
AND
order_dateSorting by one column helps.
Sorting by the other helps a different query.
But normal sorting cannot optimize both dimensions at the same time.
The Idea Behind Z-Ordering
Z-ordering creates an ordering that keeps related values physically close.
Example:
Before:
File 1
Customer 100 Jan 1Customer 9000 Jan 30Customer 200 Jan 2Customer 8000 Jan 29After Z-ordering:
File 1
Customer 100 Jan 1Customer 101 Jan 1Customer 102 Jan 2
File 2
Customer 8900 Jan 29Customer 8950 Jan 29Customer 9000 Jan 30Rows with similar values are stored near each other.
What Happens During Z-Ordering?
When you run:
OPTIMIZE salesZORDER BY (customer_id, order_date);Databricks does not simply update metadata.
It performs a physical rewrite.
The process:
Existing Files
| v
Read Data
| v
Reorganize Rows
| v
Write New Parquet Files
| v
Update Delta Transaction LogThe physical data layout changes.
The metadata improves because the new files have better statistics.
Index vs Z-Ordering
The difference:
Index
Creates another structure.
Index
| v
Existing TableThe data stays where it was.
Z-Ordering
Changes the data itself.
Original Table
| v
Reorganized TableNo separate lookup structure exists.
Library Analogy
Storage
Where is the library?
Building locationLayout
How are books arranged?
Shelf organizationPartitioning
Which floor contains the books?
History floorScience floorTechnology floorIndex
A catalog telling you:
Machine Learning | vShelf 12, Row 4Z-Ordering
Physically rearranging books so related topics sit together.
Data Engineerβs Mental Model
Modern analytical systems are not primarily trying to make computation faster.
They are trying to reduce unnecessary movement of data.
The hierarchy is:
Storage
Where are bytes?
| v
Layout
How are bytes organized?
| v
Partitioning
Which large sections can we skip?
| v
Data Skipping
Which files can we ignore?
| v
Z-Ordering
How do we improve locality?
| v
Less I/O
| v
Faster QueriesFinal Takeaway
The difference between these concepts:
| Concept | Purpose |
|---|---|
| Storage | Where bytes live |
| Data Layout | How bytes are organized |
| Partitioning | Eliminate large sections of data |
| Index | Separate lookup structure |
| Z-ordering | Physically organize data for locality |
| Data Skipping | Avoid reading unnecessary files |
The fundamental goal behind all of them is the same:
Read less data, move fewer bytes, and make analytical queries faster.