This topic introduces key indexes in Hologres, such as the distribution key, event time column (segment key), and clustering key, to help you get started with indexes and improve query performance during Hologres development.
How Hologres works
Hologres is a distributed data warehouse that uses parallel and vector computing to deliver query responses in seconds. Because of this architecture, data distribution is critical for performance. This includes how data is balanced across distributed nodes, which is governed by the distribution key, and how data is ordered within the files on a single node, which is governed by the event time column (also known as segment key). Hologres uses a columnar storage format by default for online analytical processing (OLAP) scenarios, making the order of data within a file, which is governed by the clustering key, also essential. Mastering these three concepts is key to optimizing performance. Because these data layout properties are set when data is written and are costly to change, we recommend that you design your tables with these three attributes from the start. Attributes that do not directly affect data layout, such as bitmap indexes and dictionary encoding, can be adjusted later as needed.
Hologres uses a three-level metadata structure: Database > Schema > Table. To avoid cross-database queries, we recommend grouping logically related tables under the same schema. A database is a basic unit for metadata isolation, not resource isolation.
SQL optimization basics
Designing tables with an appropriate data distribution strategy enables SQL queries to quickly locate data. This reduces I/O, consumes fewer computing resources, and achieves higher query performance. A balanced data distribution also ensures concurrent resources are used efficiently, avoiding single-point bottlenecks. The following diagram illustrates how a SQL query retrieves data and how I/O is reduced.
-
Partition pruning: When a SQL query targets a partitioned table, the query optimizer uses partition pruning to locate the relevant partitions. If the query's filter conditions do not include the partition key, the query must scan all partitions, which causes excessive I/O. As a general rule, partitioning by day is a good practice. Partition pruning is skipped for non-partitioned tables.
-
Shard pruning: Use the distribution key to quickly locate the data shard that contains the required data. This reduces resource consumption for a single query and supports higher throughput for concurrent queries. If a specific shard cannot be located, the distributed framework schedules all shards to participate in the computation. This increases the parallelism for a single query but uses more resources and lowers overall concurrency. Some operators that require centralized execution can also introduce extra shuffle overhead. As a best practice, choose columns with even data distribution, such as order IDs, user IDs, or event IDs, as the distribution key. If multiple tables that need to be joined share the same distribution key, related data is co-located on the same shard. This enables efficient local join operations.
-
Segment key pruning: Use the segment key (event time column) to quickly locate the specific data file within a node, which avoids accessing unnecessary files. If data cannot be filtered at this level, all files must be scanned.
-
Clustering key pruning: Use the clustering key to quickly locate data segments within a single file. This improves the efficiency of range queries and column sorting.
SQL optimization in practice
This section uses TPC-H queries to demonstrate how to set Hologres indexes for better query performance. For more information about TPC-H, see Test plan overview.
TPC-H SQL reference
TPC-H Q1 query
The TPC-H Q1 query performs aggregations and filtering on specific columns of the lineitem table. It includes the following condition:
l_shipdate <=: This is a filter condition. To support efficient range filtering and quickly retrieve the required data, you must define an appropriate index.
--TPC-H Q1
SELECT
l_returnflag,
l_linestatus,
SUM(l_quantity) AS sum_qty,
SUM(l_extendedprice) AS sum_base_price,
SUM(l_extendedprice * (1 - l_discount)) AS sum_disc_price,
SUM(l_extendedprice * (1 - l_discount) * (1 + l_tax)) AS sum_charge,
AVG(l_quantity) AS avg_qty,
AVG(l_extendedprice) AS avg_price,
AVG(l_discount) AS avg_disc,
COUNT(*) AS count_order
FROM
lineitem
WHERE
l_shipdate <= DATE '1998-12-01' - INTERVAL '120' DAY
GROUP BY
l_returnflag,
l_linestatus
ORDER BY
l_returnflag,
l_linestatus;
TPC-H Q4 query
The TPC-H Q4 query primarily joins the lineitem and orders tables. It includes the following conditions:
-
o_orderdate >= DATE '1996-07-01': This is a filter condition. To support efficient range filtering and quickly retrieve the required data, you must define an appropriate index. -
l_orderkey = o_orderkey: This is a join condition between the two tables. For best performance, use the same index on both tables to enable a local join, which reduces data shuffling during the operation.--TPC-H Q4 Query SELECT o_orderpriority, COUNT(*) AS order_count FROM orders WHERE o_orderdate >= DATE '1996-07-01' AND o_orderdate < DATE '1996-07-01' + INTERVAL '3' MONTH AND EXISTS ( SELECT * FROM lineitem WHERE l_orderkey = o_orderkey AND l_commitdate < l_receiptdate ) GROUP BY o_orderpriority ORDER BY o_orderpriority;
Table creation recommendations
The Q1 and Q4 queries involve the lineitem and orders tables.
hologres_dataset_tpch_100g.lineitem
Both the Q1 and Q4 queries involve the lineitem table, but they use different columns and conditions.
-
For the Q1 query: The query primarily uses
l_shipdatefor range filtering. The clustering key accelerates range scans by leveraging the sorted order of data within files. Therefore, setl_shipdateas the clustering key. The segment key (event time column) maintains order between files. For a monotonically increasing or decreasing date column, setting it as the segment key enables effective segment key pruning. Therefore, you can also setl_shipdateas the segment key. -
For the Q4 query: The query joins the
lineitemtable with theorderstable on thel_orderkeyando_orderkeycolumns. The distribution key specifies the data distribution strategy. The system places data with the same key value on the same shard. If two tables are in the same table group and are joined on their distribution key columns, the system automatically distributes matching records to the same shard during data writes. When these tables are joined, the system performs a local join on each node without shuffling data across the network. This avoids runtime data shuffling and redistribution, significantly improving execution efficiency. Therefore, setl_orderkeyas the distribution key. -
The final table structure for
lineitemis as follows:BEGIN; CREATE TABLE hologres_dataset_tpch_100g.lineitem ( l_ORDERKEY BIGINT NOT NULL, L_PARTKEY INT NOT NULL, L_SUPPKEY INT NOT NULL, L_LINENUMBER INT NOT NULL, L_QUANTITY DECIMAL(15,2) NOT NULL, L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL, L_DISCOUNT DECIMAL(15,2) NOT NULL, L_TAX DECIMAL(15,2) NOT NULL, L_RETURNFLAG TEXT NOT NULL, L_LINESTATUS TEXT NOT NULL, L_SHIPDATE TIMESTAMPTZ NOT NULL, L_COMMITDATE TIMESTAMPTZ NOT NULL, L_RECEIPTDATE TIMESTAMPTZ NOT NULL, L_SHIPINSTRUCT TEXT NOT NULL, L_SHIPMODE TEXT NOT NULL, L_COMMENT TEXT NOT NULL, PRIMARY KEY (L_ORDERKEY,L_LINENUMBER) ) WITH ( distribution_key = 'L_ORDERKEY',--Enables local join. clustering_key = 'L_SHIPDATE',--Accelerates range filtering. event_time_column = 'L_SHIPDATE'--Accelerates segment key pruning. ); COMMIT;
hologres_dataset_tpch_100g.orders
In this example, the orders table is used in the Q4 query.
-
Set the
o_orderkeycolumn of theorderstable as the distribution key to leverage local join capabilities and improve join query efficiency. -
The
o_orderdatecolumn is primarily used for date filtering. Set it as the segment key to accelerate segment key pruning. -
The final table structure for
ordersis as follows:BEGIN; CREATE TABLE hologres_dataset_tpch_100g.orders ( O_ORDERKEY BIGINT NOT NULL PRIMARY KEY, O_CUSTKEY INT NOT NULL, O_ORDERSTATUS TEXT NOT NULL, O_TOTALPRICE DECIMAL(15,2) NOT NULL, O_ORDERDATE timestamptz NOT NULL, O_ORDERPRIORITY TEXT NOT NULL, O_CLERK TEXT NOT NULL, O_SHIPPRIORITY INT NOT NULL, O_COMMENT TEXT NOT NULL ) WITH ( distribution_key = 'O_ORDERKEY',--Enables local join. event_time_column = 'O_ORDERDATE'--Accelerates segment key pruning. ); COMMIT;
Import sample data
You can quickly import 100 GB of TPC-H data into your Hologres instance using the Import public datasets with a few clicks feature in HoloWeb. In HoloWeb, select Data Solutions from the top navigation bar, and then click Import public datasets with a few clicks in the left-side navigation pane. On the configuration page, select an Instance Name (for example, holo_test) and a Database. Then, select tpch_100g from the Public Dataset Name list. The system automatically generates a non-editable SQL script at the bottom of the page. This script includes statements to create the hologres_foreign_dataset_tpch_100g and hologres_dataset_tpch_100g schemas, and to sequentially import data into foreign tables such as customer, lineitem, nation, orders, part, partsupp, region, and supplier.
Performance test results
This section compares query performance before and after setting the recommended table properties (indexes).
-
Test environment
-
Instance specification: 32-core
-
Network type: VPC
-
Execute each query twice using a PSQL client and record the latency of the second execution.
-
-
Conclusion
-
For filtered queries on a single table, setting the filter column as the clustering key effectively accelerates the query.
-
For multi-table join queries, setting the join columns as the distribution key significantly improves join efficiency.
Query
Latency with indexes
Latency without indexes
Q1
48.293 ms
59.483 ms
Q4
822.389 ms
3027.957 ms
-
References
More information
Technical principles
Deep dive into the core technical principles of Hologres (architecture, storage engine, and compute engine): Core Technology of Alibaba Cloud's Cloud-native Real-time Data Warehouse.
Service activation
-
Choosing specifications: Instance management.
-
RAM user authorization: Quick start for RAM user authorization.
Data import
-
Real-time writes and dimension table queries with Flink: Realtime Compute for Apache Flink.
-
Real-time full synchronization from databases such as MySQL, Oracle, and PolarDB: Configure a MySQL data source.
-
Import data from OSS: Accelerate access to OSS data lakes by using DLF.
-
Use Fixed Plan to increase data write and update efficiency by 10 times. For more information, see Accelerate SQL execution by using Fixed Plan.
Data query
-
Table creation recommendations for different use cases: Scenario-based table tuning guide.
-
Before you create tables, understand key parameters such as
distribution_key,clustering_key,event_time_column, andbitmap_index. Using appropriate syntax and indexes to define an optimal table structure significantly improves performance. For more information, see CREATE TABLE. -
Internal table performance tuning: Optimize query performance.
-
MaxCompute acceleration: Accelerate MaxCompute data queries by using foreign tables.
O&M and monitoring
-
Active queries (troubleshoot running queries, and check for existing or potential locks): Manage queries.
-
Slow queries (troubleshoot failed or long-running queries): Get and analyze slow query logs.
-
Read/write splitting and load isolation: Deploy read/write splitting for primary and secondary instances (shared storage).
Use cases and best practices
Practices and use cases: Best practices and classic customer use cases for typical industry scenarios.