Distributed columnar index

更新时间:
复制 MD 格式

The columnar index (IMCI) feature in PolarDB for PostgreSQL Distributed Edition integrates the DuckDB analytical engine to boost analytical query performance by over 60 times. Combined with the transparent sharding mechanism of its distributed architecture, queries can be pushed down to multiple data nodes (DNs) for parallel processing, allowing analytical performance to scale linearly with the number of nodes. For terabyte- or petabyte-scale datasets, the combination of a distributed architecture and IMCI can improve overall analytical performance by nearly 100 times compared to a row-store implementation, making it ideal for HTAP (Hybrid Transactional and Analytical Processing) scenarios.

Architecture

image

The distributed architecture with IMCI includes the following core components:

  • Coordinator node (CN): Receives requests, generates a distributed execution plan, pushes down SQL queries to the data nodes, and aggregates the results from all DNs before returning them to the client.

  • Data node (DN): Stores data in both row-store and column-store (IMCI) formats. Data from the row-store is asynchronously written to the column-store via logical replication. This process ensures that analytics acceleration is compatible with real-time data writes.

The following example describes the workflow for a typical analytical aggregation query:

  1. The CN generates a distributed plan and dispatches SQL queries. The CN receives a business SQL request. The CN generates a distributed execution plan based on global metadata and determines how to split and push the query down to the relevant data nodes.

  2. DNs perform parallel queries on IMCI data. The CN pushes the query down to the target DNs. Each DN performs efficient parallel queries and initial aggregations on its local IMCI data, then returns the intermediate results to the CN.

  3. The CN performs a final aggregation and returns the result. The CN gathers the query results from all DNs, performs final aggregations or sorting as needed, and returns the final result to the user or application.

Use cases

This feature is ideal for multi-tenant database scenarios, especially when you need to efficiently perform rollups and global aggregations across tenant data. This feature applies to the following two sharding scenarios:

Horizontal sharding (by tenant_id)

Consider a business table named orders that uses tenant_id as the sharding key.

  • Aggregate data for a single tenant: Calculate the total and average order amount for a specific tenant.

    SELECT SUM(amount) AS total_amount, AVG(amount) AS avg_amount
    FROM orders
    WHERE tenant_id = 1001;
  • Aggregate data across all tenants: Calculate the total and average order amount for all tenants, grouped by tenant.

    SELECT tenant_id, SUM(amount) AS total_amount, AVG(amount) AS avg_amount
    FROM orders
    GROUP BY tenant_id;

Vertical sharding (by schema)

Consider that each tenant's data is stored in a separate schema, and the table name is orders in all schemas.

  • Aggregate data for a single schema: Calculate the total and average order amount within a specific schema.

    SELECT SUM(amount) AS total_amount, AVG(amount) AS avg_amount
    FROM tenant_a.orders;
  • Aggregate data across all tenants: Calculate the total and average order amount for all tenants by using UNION ALL.

    SELECT 'tenant_a' AS tenant, SUM(amount) AS total_amount, AVG(amount) AS avg_amount FROM tenant_a.orders
    UNION ALL
    SELECT 'tenant_b' AS tenant, SUM(amount) AS total_amount, AVG(amount) AS avg_amount FROM tenant_b.orders;

Prerequisites

Configure the distributed columnar index

Step 1: Enable distributed IMCI

You can modify the following parameters in the PolarDB console or within a database session:

Parameter

Description

polar_cluster_enable_imci

Enables or disables the distributed columnar index feature.

  • on: Enables the feature.

  • off (default): Disables the feature.

polar_csi.enable_anyall_to_in

Controls whether IN expressions in WHERE clauses can use the distributed columnar index.

  • on: Enables this optimization.

  • off (default): Disables this optimization.

pg_hint_plan.polar_enable_distributed_hint

Enables or disables the distributed hint feature.

  • on: Enables hints.

  • off (default): Disables hints.

SET polar_cluster_enable_imci = on;
SET polar_csi.enable_anyall_to_in = on;
SET pg_hint_plan.polar_enable_distributed_hint = on;

Step 2: Create replication slots

Use an account with high privileges to run the following command on the primary CN. This creates a replication slot on all nodes for synchronization between the row-store and column-store.

SELECT run_command_on_all_nodes($$ SELECT polar_csi_start_sync() $$);
Note

This operation is idempotent, meaning it can be safely run multiple times without side effects.

Step 3: Create and shard tenant tables

Horizontal sharding

Create a distributed table using tenant_id as the sharding key:

Note

If you use tenant_id as the sharding key, it must be the primary key or part of the primary key.

-- Create the initial business table with tenant_id as part of the primary key
CREATE TABLE orders (
  order_id   bigint,
  tenant_id  int NOT NULL,
  amount     numeric(20,2),
  status     text,
  create_time timestamp,
  PRIMARY KEY (tenant_id, order_id)
);

-- Convert it to a distributed sharded table
SELECT create_distributed_table('orders', 'tenant_id');

Vertical sharding

Store each tenant's data in a separate schema:

-- Create a schema for the tenant
CREATE SCHEMA tenant1;

-- Enable distributed management for the schema
SELECT polar_cluster_schema_distribute('tenant1');

-- Create the business table
SET search_path TO tenant1;

CREATE TABLE orders (
  order_id   bigint,
  tenant_id  int NOT NULL,
  amount     numeric(20,2),
  status     text,
  create_time timestamp,
  PRIMARY KEY (tenant_id, order_id)
);

Step 4: Create a columnar index

Create a columnar index (CSI) on the table:

-- Create a columnar index on all columns
CREATE INDEX csi_orders ON orders USING CSI;

-- Create a columnar index on specific columns (e.g., for queries on tenant_id, order_id, and amount)
CREATE INDEX csi_orders_part ON orders1 USING CSI(tenant_id, order_id, amount);

-- Create a columnar index without locking the table (Recommended)
CREATE INDEX CONCURRENTLY csi_orders ON orders USING CSI;
Note

We recommend creating a CSI on all columns to prevent column-store queries from failing due to missing columns.

Step 5: Execute queries with columnar index

Two parameters control whether a query uses the columnar index:

Parameter

Description

polar_csi.enable_query

Controls whether queries can use a columnar index.

  • on: Enables usage.

  • off (default): Disables usage.

polar_csi.cost_threshold

Sets the cost threshold for a query. If the estimated cost exceeds this threshold, the query uses the column-store engine. Otherwise, it uses the row-store engine.

  • Value range: 0 to 1000000000

  • Default value: 50000

We recommend using a hint to force a specific query to use the columnar index:

/*+SET (polar_csi.enable_query on) SET(polar_csi.cost_threshold 0)*/
SELECT tenant_id, SUM(amount) AS total_amount, AVG(amount) AS avg_amount
FROM orders
GROUP BY tenant_id;

You can also set these parameters globally or per user account. To set them globally, modify the parameters in the PolarDB console. To set them for a user, run the following statements on the primary CN:

-- Prioritize using the columnar index for the user 'test'
ALTER ROLE test SET polar_csi.enable_query = ON;
ALTER ROLE test SET polar_csi.cost_threshold = 0;

Step 6: Verify columnar index usage

You can use EXPLAIN for analysis. If CSI Executor appears in the execution plan, it indicates that the columnar index is used successfully:

/*+SET (polar_csi.enable_query on) SET(polar_csi.cost_threshold 0)*/
EXPLAIN (COSTS OFF) SELECT tenant_id, SUM(amount) AS total_amount, AVG(amount) AS avg_amount
FROM orders
GROUP BY tenant_id;

Example output snippet (The CSI Executor indicates that the query used the column-store engine):

                       QUERY PLAN
---------------------------------------------------------
 Custom Scan (PolarCluster Adaptive)
   Task Count: 32
   Tasks Shown: One of 32
   ->  Task
         Node: host=127.0.0.1 port=45719 dbname=postgres
         ->  CSI Executor:
             ┌───────────────────────────┐
             │       HASH_GROUP_BY       │
             │    ────────────────────   │
             │        Aggregates:        │
             │          sum(#1)          │
             │          avg(#2)          │
             └─────────────┬─────────────┘
             ┌─────────────┴─────────────┐
             │         SEQ_SCAN          │
             │    ────────────────────   │
             │    Table: orders_102008   │
             │   Type: Sequential Scan   │
             └───────────────────────────┘

Performance

The following tests demonstrate the horizontal scalability and performance of the distributed architecture combined with IMCI in different data processing scenarios. Each DN in the test environment has 16 cores and 64 GB of memory.

  • Sysbench Online Transaction Processing (OLTP) test: This test evaluates the database's performance under high-concurrency transactional operations such as inserts, updates, and deletes. As the number of data nodes (DNs) increases, the system's write throughput scales almost linearly to support growing business traffic.

  • TPC-H Online Analytical Processing (OLAP) test: This test focuses on the performance of large-scale data aggregation and complex analytical queries. IMCI significantly improves single-node analytical performance, while the distributed architecture parallelizes queries across multiple DNs. This combination allows query performance to scale linearly with the number of nodes, making it suitable for analyzing and gaining insights from massive datasets.

TPC-H performance test

Using a 1 TB TPC-H dataset, we measured the query latency with 1, 2, 4, 8, and 12 DNs.

image

The test results show that:

  • The query latency of the distributed column-store is over 100 times lower than that of the distributed row-store, and performance scales linearly.

  • Compared to a single-node columnar query, the distributed architecture with IMCI also achieves linear performance gains as the number of DNs increases. A 12-DN configuration provides a tenfold performance improvement over a single-node setup.

Sysbench OLTP_INSERT test

We measured the write QPS of the distributed cluster with 1, 2, 4, 8, and 12 DN configurations.image

The test results show that:

  • Write QPS scales linearly with the number of DNs: As the number of DNs increases from 1 to 12, the write QPS shows near-linear growth, reaching a maximum of 1.6 million QPS with 12 DNs.

  • The distributed architecture horizontally scales data synchronization: The parallel, multi-DN architecture improves write performance and enhances logical replication replay. This enables near real-time data synchronization from row-store to column-store (IMCI).