In PostgreSQL, partitioning is an effective way to handle continuously growing data, and partition pruning speeds up queries. PolarDB for PostgreSQL also supports IMCIs on partitioned tables, further meeting statistical and analytical requirements on partitioned data.
Background
As business systems keep running, historical data accumulates and tables grow larger. A common practice is to partition data by dimensions such as time or user_id so that each partition holds only a subset of the data. When you query the data, native PostgreSQL also uses partition pruning to avoid reading unrelated data.
IMCIs in PolarDB for PostgreSQL also accelerate analytical queries on partitioned tables. You use them the same way you use existing indexes on partitioned tables.
Results
At a degree of parallelism of 4, the IMCI is more than 35 times faster than native PostgreSQL parallel execution for all three test queries.
|
Query |
Native PostgreSQL parallel execution |
IMCI |
|
Q1 |
2.13 s |
0.05 s |
|
Q2 |
6.42 s |
0.18 s |
|
Q3 |
10.51 s |
0.30 s |
Procedure
Step 1: Prepare the environment
-
Verify that your cluster version and configuration meet the following requirements:
-
Cluster versions:
-
PostgreSQL 14 (minor engine version 2.0.14.10.20.0 or later)
-
PostgreSQL 15 (minor engine version 2.0.15.15.7.0 or later)
-
PostgreSQL 16 (minor engine version 2.0.16.8.3.0 or later)
-
PostgreSQL 17 (minor engine version 2.0.17.7.5.0 or later)
NoteYou can view the minor engine version in the console or by running the
SHOW polardb_version;statement. If the minor engine version does not meet the requirements, upgrade the minor engine version。 -
-
The
wal_levelparameter must be set tological. This setting adds the required information for logical decoding to the write-ahead logging (WAL).NoteYou can set the wal_level parameter in the console. Modifying this parameter restarts the cluster. Plan your business operations accordingly and proceed with caution.
-
The source table must have a primary key, and the primary key column must be included when you create the columnstore index. Using a
SERIALorBIGSERIALdata type for the primary key is recommended, as it significantly improves data synchronization efficiency. -
You can create only one columnstore index for each table.
-
-
Enable the IMCI feature.
The method for enabling IMCI varies depending on the minor engine version of your PolarDB for PostgreSQL cluster:
Step 2: Prepare the data
This case creates a multi-level partitioned table, inserts about 320 million rows (~16 GB) of simulated data, and then runs statistical analysis based on partition conditions.
The schema of the test partitioned table is as follows:
-
sales: the primary table. -
sales_2023: partitioned by year.-
sales_2023_a: partitioned by month; months 1 through 6 are defined as partition a. -
sales_2023_b: partitioned by month; months 7 through 12 are defined as partition b.
-
-
sales_2024: partitioned by year.-
sales_2024_a: partitioned by month; months 1 through 6 are defined as partition a. -
sales_2024_b: partitioned by month; months 7 through 12 are defined as partition b.
-
-
Create a multi-level partitioned table named
sales, with the time columnsale_dateas the partition key. The definition is as follows:CREATE TABLE sales ( sale_id serial, product_id int NOT NULL, sale_date date NOT NULL, amount numeric(10,2) NOT NULL, primary key(sale_id, sale_date) ) PARTITION BY RANGE (sale_date); CREATE TABLE sales_2023 PARTITION OF sales FOR VALUES FROM ('2023-1-1') TO ('2024-1-1') PARTITION BY RANGE (sale_date); CREATE TABLE sales_2023_a PARTITION OF sales_2023 FOR VALUES FROM ('2023-1-1') TO ('2023-7-1'); CREATE TABLE sales_2023_b PARTITION OF sales_2023 FOR VALUES FROM ('2023-7-1') TO ('2024-1-1'); CREATE TABLE sales_2024 PARTITION OF sales FOR VALUES FROM ('2024-1-1') TO ('2025-1-1') PARTITION BY RANGE (sale_date); CREATE TABLE sales_2024_a PARTITION OF sales_2024 FOR VALUES FROM ('2024-1-1') TO ('2024-7-1'); CREATE TABLE sales_2024_b PARTITION OF sales_2024 FOR VALUES FROM ('2024-7-1') TO ('2025-1-1'); -
Generate the data and insert it into the partitioned table (about 16 GB).
INSERT INTO sales (product_id, sale_date, amount) SELECT (random()*100)::int AS product_id, '2023-01-1'::date + i/3200000*7 AS sale_date, (random()*1000)::numeric(10,2) AS amount FROM generate_series(1, 320000000) i; -
Create an IMCI on the table and include the
sale_id,product_id,sale_date, andamountcolumns in the IMCI.CREATE INDEX ON sales USING CSI(sale_id, product_id, sale_date, amount);
Step 3: Run the queries
Run queries by using different execution engines. Three queries (Q1, Q2, and Q3) are generated based on different partition conditions.
-
Use the IMCI.
--- Enable the IMCI and set the query degree of parallelism to 4. SET polar_csi.enable_query to on; // High kernel version SET polar_csi.max_parallel_workers to 4; // Low kernel version SET polar_csi.exec_parallel to 4; --- Q1 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-3-1' AND amount > 100 GROUP BY sale_date; --- Q2 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-9-1' AND amount > 100 GROUP BY sale_date; --- Q3 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2024-3-1' AND amount > 100 GROUP BY sale_date;NoteThe
polar_csi.max_parallel_workersparameter was previously namedpolar_csi.exec_parallelin earlier kernel versions. For kernel versions that do not supportpolar_csi.max_parallel_workers, usepolar_csi.exec_parallelinstead.-
PostgreSQL 14:
-
Use
polar_csi.exec_parallelin versions 2.0.14.20.42.0 and earlier. -
Use
polar_csi.max_parallel_workersin versions 2.0.14.20.43.0 and later.
-
-
PostgreSQL 16:
-
Use
polar_csi.exec_parallelin versions 2.0.16.11.15.0 and earlier. -
Use
polar_csi.max_parallel_workersin versions 2.0.16.13.16.0 and later.
-
-
-
Disable the IMCI and use the row-store engine.
--- Disable the IMCI, use the row-store engine, and set the query degree of parallelism to 4. SET polar_csi.enable_query to off; SET max_parallel_workers_per_gather to 4; --- Q1 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-3-1' AND amount > 100 GROUP BY sale_date; --- Q2 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-9-1' AND amount > 100 GROUP BY sale_date; --- Q3 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2024-3-1' AND amount > 100 GROUP BY sale_date;