Semi-structured data has become a standard part of modern analytics. Whether you're storing application logs, telemetry, user attributes, event metadata, or feature flags, it's common to encounter records where every row contains a different set of key-value pairs.
ClickHouse® provides the Map data type to handle these dynamic datasets without requiring hundreds of nullable columns or repeatedly parsing JSON during query execution. A Map offers both flexibility and a clean schema for attributes that vary from one record to another.
However, querying individual keys from large Map columns has traditionally been less efficient than querying regular columns. Prior to ClickHouse® 26.3, retrieving a single key often required processing the serialized map representation for every row, even when only one value was needed.
ClickHouse® 26.3 introduces bucketed Map serialization, a new storage format designed to make selective key lookups significantly faster. By reorganizing how map data is stored on disk, ClickHouse® reduces the amount of data that must be processed during queries while preserving the fast insert performance that the database is known for.
In this article, we'll explore:
- How
Mapserialization worked before ClickHouse® 26.3 - Why selective key lookups were expensive
- How bucketed serialization works
- The available configuration settings
- Expected performance improvements
- When you should enable this feature
Understanding the Map Data Type
A Map stores key-value pairs inside a single column.
For example:
CREATE TABLE events
(
event_time DateTime,
user_id UInt64,
attributes Map(String, String)
)
ENGINE = MergeTree
ORDER BY event_time;
A row might contain:
{
"country": "India",
"browser": "Chrome",
"device": "Mobile",
"campaign": "SummerSale"
}
Another row might contain completely different attributes:
{
"country": "Germany",
"language": "German",
"membership": "Premium"
}
Instead of creating dozens or even hundreds of nullable columns, dynamic attributes remain grouped inside a single Map.
This makes the data model both simpler and more flexible.
How Map Serialization Worked Before ClickHouse® 26.3
Internally, a Map is stored as two arrays:
- Keys
- Values
Conceptually:
Keys:
["country", "browser", "campaign"]
Values:
["India", "Chrome", "SummerSale"]
Suppose a query requests:
SELECT attributes['browser']
FROM events;
Although only one key is needed, ClickHouse® still has to process the serialized map representation for every row in order to locate the requested key.
For small maps, this overhead is usually negligible.
For maps containing dozens or hundreds of keys, the additional work becomes much more noticeable.
Conceptually, the process looks like this:
Map
country
browser
device
campaign
source
region
...
↓
Query:
attributes['browser']
↓
Process serialized map
Locate requested key
Return value
The larger each map becomes, the more work ClickHouse® performs for every lookup.
Why This Becomes a Performance Bottleneck
Imagine each row stores 100 different attributes.
A dashboard might only need:
attributes['country']
Even though only one key is requested, the database still has to inspect the serialized map representation for every row.
Across billions of rows, this additional processing increases:
- Data read
- CPU utilization
- Query latency
As maps continue to grow, the cost of repeatedly locating individual keys also grows.
Bucketed Map Serialization in ClickHouse® 26.3
ClickHouse® 26.3 introduces a new serialization format called with_buckets.
Instead of storing every key-value pair together as a single serialized structure, map entries are distributed across multiple buckets according to the hash of each key.
Conceptually:
Bucket 1
country
city
zip
----------------
Bucket 2
browser
device
----------------
Bucket 3
campaign
source
medium
Now consider the same query:
SELECT attributes['browser']
FROM events;
Rather than processing the entire serialized map, ClickHouse® determines which bucket may contain the requested key and reads only that portion of the data.
The workflow now becomes:
Query
attributes['browser']
↓
Hash("browser")
↓
Locate Bucket 2
↓
Read Bucket 2 only
↓
Return value
This significantly reduces the amount of data that must be processed for selective key lookups.
How Bucketed Serialization Works
One of the clever aspects of this feature is when the optimization occurs.
Bucketing is not performed during inserts.
Instead, newly inserted parts continue using the existing serialization format.
During MergeTree background merges, ClickHouse® automatically rewrites eligible parts into the bucketed storage layout.
This design offers two major advantages.
First, insert performance remains fast because ingestion isn't slowed by additional bucketing work.
Second, read performance gradually improves as background merges reorganize the stored data.
Applications don't need to change their SQL queries.
The optimization happens entirely within the storage layer.
Configuration Options
ClickHouse® 26.3 introduces several settings that control bucketed serialization.
map_serialization_version
Determines which serialization format should be used.
map_serialization_version_for_zero_level_parts
Specifies the serialization used for newly created parts before background merges occur.
max_buckets_in_map
Defines the maximum number of buckets available for storing map entries.
Increasing the bucket count can improve selective key access for larger maps but also introduces additional metadata and storage overhead.
map_buckets_strategy
Controls how ClickHouse® chooses the appropriate number of buckets for a given map.
map_buckets_min_avg_size
Defines the minimum average map size before bucketed serialization becomes worthwhile.
These settings allow administrators to balance storage efficiency with query performance according to their workload.
Performance Improvements
According to the ClickHouse® 26.3 release information, bucketed serialization can dramatically improve queries that retrieve individual keys from large Map columns.
The observed improvements depend on several factors, including:
- Average number of keys per map
- Data distribution
- Query patterns
- Bucket configuration
For some workloads, ClickHouse® reports 2× to 49× faster single-key lookups compared to the previous serialization format.
The greatest improvements occur when:
- Maps contain many keys
- Queries repeatedly access only a few keys
- Large amounts of data are scanned
- Interactive dashboards repeatedly query the same attributes
As with any performance optimization, results depend on workload characteristics. Smaller maps or queries that read the entire map may experience limited improvements.
Example
Consider a log analytics table.
CREATE TABLE logs
(
timestamp DateTime,
metadata Map(String, String)
)
ENGINE = MergeTree
ORDER BY timestamp;
Example metadata:
service
host
region
environment
cluster
namespace
container
status
trace_id
version
Suppose a dashboard runs:
SELECT
metadata['service'],
count()
FROM logs
GROUP BY metadata['service'];
Prior to bucketed serialization, ClickHouse® would process the serialized map representation to locate the service key for every row.
After background merges rewrite the data into the bucketed format, ClickHouse® can identify the appropriate bucket and process only the relevant portion of the map.
The SQL query remains identical.
Only the storage layout changes.
When Should You Use Bucketed Serialization?
This feature is particularly valuable for workloads that:
- Store large
Mapcolumns - Frequently retrieve individual keys
- Analyze billions of rows
- Process application logs
- Collect observability metrics
- Store telemetry data
- Analyze event metadata
- Build interactive dashboards
If your maps are very small or most queries retrieve the complete map, the performance gains may be relatively modest.
Best Practices
To get the most from bucketed serialization:
- Enable it for workloads with large
Mapcolumns. - Allow MergeTree background merges to complete before benchmarking.
- Select bucket counts appropriate for your average map size.
- Benchmark using your own production workloads.
- Don't expect significant improvements if most queries read the entire map rather than individual keys.
Things to Keep in Mind
Before enabling the feature, remember a few important points.
- Existing data isn't rewritten immediately after upgrading.
- Bucketed serialization is applied gradually through MergeTree background merges.
- Insert performance remains largely unchanged because bucketing isn't performed during ingestion.
- Query improvements depend heavily on workload characteristics and access patterns.
Understanding these behaviors helps set realistic expectations during evaluation.
Why This Matters
Many modern analytical workloads rely heavily on dynamic attributes that continuously evolve.
Application logs, telemetry, user events, feature flags, and metadata often contain different fields for every record.
The Map data type provides the flexibility needed for these datasets, but fast access to individual keys is equally important for interactive analytics.
Bucketed serialization improves the physical storage layout without changing the SQL interface.
Existing applications continue using the same queries while benefiting from reduced I/O and faster selective key lookups once background merges have reorganized the data.
Conclusion
Bucketed Map serialization is one of the most practical storage optimizations introduced in ClickHouse® 26.3.
Rather than treating every map as a single serialized structure, ClickHouse® now organizes map entries into buckets, allowing queries to process only the portion of the data that may contain the requested key.
The optimization happens automatically during MergeTree background merges, preserving fast insert performance while significantly improving read efficiency for many analytical workloads.
Depending on data characteristics and query patterns, the ClickHouse® team reports speedups ranging from 2× to 49× for selective key lookups.
For organizations working with logs, observability platforms, telemetry pipelines, event metadata, or other semi-structured datasets, bucketed serialization offers a compelling way to improve query performance without changing existing SQL queries or redesigning data models.
As always, benchmark the feature against your own workload, but if your applications frequently access individual keys within large Map columns, bucketed serialization is a feature well worth evaluating after upgrading to ClickHouse® 26.3.
References
- ClickHouse® 26.3 Release Notes – https://clickhouse.com/blog/clickhouse-release-26-03
- ClickHouse® Map Data Type Documentation – https://clickhouse.com/docs/sql-reference/data-types/map
- ClickHouse® MergeTree Documentation – https://clickhouse.com/docs/engines/table-engines/mergetree-family/mergetree
Top comments (0)