ClickHouse for SQL Server DBAs - Optimizing Query Performance with Skipping Indexes in ClickHouse

Enhance Query Speed in ClickHouse Using Skipping Indexes


4 min read

In ClickHouse, narrow indexes, often referred to as "skipping indexes" or "data skipping indexes," are used to improve query performance by allowing the system to skip over blocks of data that do not match the query conditions. This is particularly effective in reducing the amount of data read from disk, thus accelerating query execution, especially in large datasets. Here’s a detailed overview of how narrow indexes are implemented and used in ClickHouse:

Concept of Narrow Indexes

Narrow indexes in ClickHouse are not traditional indexes that point to individual rows or columns. Instead, they are lightweight structures associated with table data parts, typically stored in separate files. Each index entry corresponds to a block of data (or a data part) and contains the minimum and maximum values of a particular column for that block. When a query is executed, ClickHouse uses these indexes to determine quickly if a block contains relevant data based on the query's WHERE clause conditions. If the index indicates that a block cannot contain any matching data, that block is skipped entirely during query execution.

Types of Narrow Indexes in ClickHouse

ClickHouse supports several types of narrow indexes:

  1. MinMax Index: Automatically created for all columns when using the MergeTree family of table engines. It stores the minimum and maximum values of each column for each data part.

  2. Primary Key Index: While technically part of the sorting key in MergeTree tables, the primary key index also acts as a skipping index because data is sorted by the primary key. This allows ClickHouse to quickly narrow down the data blocks that need to be scanned for queries filtered on the primary key columns.

  3. Bloom Filter Index: Used for strings or fixed-length byte arrays. It allows for probabilistic checks whether a block contains certain values, reducing false negatives and efficiently skipping irrelevant blocks.

  4. Set Index: This index works by storing a set of distinct values for a column in each block. It is useful for queries with IN conditions.

Implementation Steps

Here’s how you can implement a narrow index in ClickHouse, using a MinMax index as an example:

  1. Create Table with Index: Define a MergeTree table and specify the columns for which you want to enable skipping indexes. Here’s an example with a MinMax index:

     CREATE TABLE example (
         date Date,
         event_name String,
         user_id UInt32,
         revenue Float32
     ) ENGINE = MergeTree()
     ORDER BY (date, user_id)
     SETTINGS index_granularity = 8192;

    In this setup, ClickHouse automatically creates MinMax indexes for all columns.

  2. Querying with Index Utilization: When you execute a query, ClickHouse evaluates whether it can use the MinMax index to skip blocks. For example:

     SELECT sum(revenue)
     FROM example
     WHERE date BETWEEN '2020-01-01' AND '2020-01-31'
     AND event_name = 'purchase';

    For this query, ClickHouse uses the MinMax index on date and event_name to skip over blocks that do not contain data within the specified date range or the purchase event.

Benefits and Limitations


  • Reduces I/O by avoiding unnecessary reads of data blocks.

  • Improves query performance without requiring extensive indexing like traditional B-tree indexes.

  • Offers flexible indexing strategies through different types of narrow indexes.


  • Effectiveness depends on the distribution of data and query conditions.

  • Can introduce overhead during data insertion and merging.

Narrow indexes in ClickHouse are powerful tools for optimizing query performance by skipping irrelevant data, especially beneficial for large datasets where reading and processing time can be significantly reduced.

Narrow indexes in ClickHouse, also known as skipping indexes, enhance query performance by allowing the system to bypass blocks of data that don't meet query conditions, thus reducing disk read operations. These indexes are lightweight, associated with data blocks, and vary in types such as MinMax, Primary Key, Bloom Filter, and Set indexes. Implementing these indexes involves creating a table with specified columns for indexing and querying with conditions that leverage these indexes to skip irrelevant blocks. While they significantly improve query efficiency and reduce I/O operations, their effectiveness can vary based on data distribution and query types, and they may add overhead during data insertion.