<EXASOL_DB_PASSWORD>, <PRIVATE_IP>, and <PUBLIC_IP>
are used throughout. Substitute with your actual credentials when reproducing.
This comprehensive benchmark report provides complete reproduction details for performance testing of 4 database systems using the TPC-H benchmark at scale factor 100. All installation steps, configuration parameters, and a self-contained benchmark package are included for independent verification.
We compared 4 database systems:
| Database | exasol 2025.1.0 |
| Setup Method | installer |
| Cloud Provider | AWS |
| Region | eu-west-1 |
| Instance Type | r6id.8xlarge |
| CPU | Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz |
| CPU Cores | 32 vCPUs |
| Memory | 247.7GB RAM |
| Database | clickhouse 25.9.4.58 |
| Setup Method | native |
| Data Directory | /data/clickhouse |
| Cloud Provider | AWS |
| Region | eu-west-1 |
| Instance Type | r6id.8xlarge |
| CPU | Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz |
| CPU Cores | 32 vCPUs |
| Memory | 247.7GB RAM |
| Database | clickhouse 25.9.4.58 |
| Setup Method | native |
| Data Directory | /data/clickhouse |
| Cloud Provider | AWS |
| Region | eu-west-1 |
| Instance Type | r6id.8xlarge |
| CPU | Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz |
| CPU Cores | 32 vCPUs |
| Memory | 247.7GB RAM |
| Database | clickhouse 25.9.4.58 |
| Setup Method | native |
| Data Directory | /data/clickhouse |
| Cloud Provider | AWS |
| Region | eu-west-1 |
| Instance Type | r6id.8xlarge |
| CPU | Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz |
| CPU Cores | 32 vCPUs |
| Memory | 247.7GB RAM |
TPC-H is a decision support benchmark that consists of a suite of business-oriented ad-hoc queries and concurrent data modifications. The queries and data are chosen to have broad industry-wide relevance. This benchmark illustrates decision support systems that examine large volumes of data, execute queries with a high degree of complexity, and give answers to critical business questions. The benchmark models a wholesale supplier with a distribution network across multiple regions.
Nations/countries (25 rows)
Rows: ~2500
n_nationkeyn_namen_regionkeyn_commentForeign key to region
Geographic regions (5 rows)
Rows: ~500
r_regionkeyr_namer_commentParts/products catalog
Rows: ~20000000
p_partkeyp_namep_mfgrp_brandp_typep_sizep_containerp_retailpricep_commentSuppliers/vendors
Rows: ~1000000
s_suppkeys_names_addresss_nationkeys_phones_acctbals_commentForeign key to nation
Parts supplied by suppliers (association table)
Rows: ~80000000
ps_partkeyps_suppkeyps_availqtyps_supplycostps_commentForeign keys to part and supplier
Customers/buyers
Rows: ~15000000
c_custkeyc_namec_addressc_nationkeyc_phonec_acctbalc_mktsegmentc_commentForeign key to nation
Customer orders
Rows: ~150000000
o_orderkeyo_custkeyo_orderstatuso_totalpriceo_orderdateo_orderpriorityo_clerko_shippriorityo_commentForeign key to customer
Order line items (largest table)
Rows: ~600121500
l_orderkeyl_partkeyl_suppkeyl_linenumberl_quantityl_extendedpricel_discountl_taxl_returnflagl_linestatusl_shipdatel_commitdatel_receiptdatel_shipinstructl_shipmodel_commentForeign keys to orders, part, supplier, partsupp
Each database system uses optimized DDL tailored to its architecture and query optimizer.
Create 8 TPC-H tables with system-optimized data types
-- TPC-H Table Creation Script
-- Creates all 8 TPC-H tables with appropriate data types and storage options for each database system
-- Exasol table creation
-- Nation table
CREATE OR REPLACE TABLE benchmark.nation (
n_nationkey DEC(11),
n_name CHAR(25) CHARACTER SET ASCII,
n_regionkey DEC(11),
n_comment VARCHAR(152) CHARACTER SET ASCII
);
-- Region table
CREATE OR REPLACE TABLE benchmark.region (
r_regionkey DEC(11),
r_name CHAR(25) CHARACTER SET ASCII,
r_comment VARCHAR(152) CHARACTER SET ASCII
);
-- Part table
CREATE OR REPLACE TABLE benchmark.part (
p_partkey DEC(11),
p_name VARCHAR(55) CHARACTER SET ASCII,
p_mfgr CHAR(25) CHARACTER SET ASCII,
p_brand CHAR(10) CHARACTER SET ASCII,
p_type VARCHAR(25) CHARACTER SET ASCII,
p_size DEC(10),
p_container CHAR(10) CHARACTER SET ASCII,
p_retailprice DECIMAL(12,2),
p_comment VARCHAR(23) CHARACTER SET ASCII,
DISTRIBUTE BY p_partkey
);
-- Supplier table
CREATE OR REPLACE TABLE benchmark.supplier (
s_suppkey DEC(11),
s_name CHAR(25) CHARACTER SET ASCII,
s_address VARCHAR(40) CHARACTER SET ASCII,
s_nationkey DEC(11),
s_phone CHAR(15) CHARACTER SET ASCII,
s_acctbal DECIMAL(12,2),
s_comment VARCHAR(101) CHARACTER SET ASCII,
DISTRIBUTE BY s_suppkey
);
-- Partsupp table
CREATE OR REPLACE TABLE benchmark.partsupp (
ps_partkey DEC(11),
ps_suppkey DEC(11),
ps_availqty DEC(10),
ps_supplycost DECIMAL(12,2),
ps_comment VARCHAR(199) CHARACTER SET ASCII,
DISTRIBUTE BY ps_partkey
);
-- Customer table
CREATE OR REPLACE TABLE benchmark.customer (
c_custkey DEC(11),
c_name VARCHAR(25) CHARACTER SET ASCII,
c_address VARCHAR(40) CHARACTER SET ASCII,
c_nationkey DEC(11),
c_phone CHAR(15) CHARACTER SET ASCII,
c_acctbal DECIMAL(12,2),
c_mktsegment CHAR(10) CHARACTER SET ASCII,
c_comment VARCHAR(117) CHARACTER SET ASCII,
DISTRIBUTE BY c_custkey
);
-- Orders table
CREATE OR REPLACE TABLE benchmark.orders (
o_orderkey DEC(12),
o_custkey DEC(11),
o_orderstatus CHAR(1) CHARACTER SET ASCII,
o_totalprice DECIMAL(12,2),
o_orderdate DATE,
o_orderpriority CHAR(15) CHARACTER SET ASCII,
o_clerk CHAR(15) CHARACTER SET ASCII,
o_shippriority DEC(10),
o_comment VARCHAR(79) CHARACTER SET ASCII,
DISTRIBUTE BY o_custkey
);
-- Lineitem table
CREATE OR REPLACE TABLE benchmark.lineitem (
l_orderkey DEC(12),
l_partkey DEC(11),
l_suppkey DEC(11),
l_linenumber DEC(10),
l_quantity DECIMAL(12,2),
l_extendedprice DECIMAL(12,2),
l_discount DECIMAL(12,2),
l_tax DECIMAL(12,2),
l_returnflag CHAR(1) CHARACTER SET ASCII,
l_linestatus CHAR(1) CHARACTER SET ASCII,
l_shipdate DATE,
l_commitdate DATE,
l_receiptdate DATE,
l_shipinstruct CHAR(25) CHARACTER SET ASCII,
l_shipmode CHAR(10) CHARACTER SET ASCII,
l_comment VARCHAR(44) CHARACTER SET ASCII,
DISTRIBUTE BY l_orderkey
);
Create indexes on foreign keys and join columns
-- TPC-H Index Creation Script
-- Creates indexes to optimize query performance for both database systems
-- Create local indexes for Exasol
ENFORCE LOCAL INDEX ON benchmark.lineitem (l_suppkey);
ENFORCE LOCAL INDEX ON benchmark.lineitem (l_partkey, l_suppkey);
ENFORCE LOCAL INDEX ON benchmark.lineitem (l_partkey);
ENFORCE LOCAL INDEX ON benchmark.lineitem (l_orderkey);
ENFORCE LOCAL INDEX ON benchmark.nation (n_nationkey);
ENFORCE LOCAL INDEX ON benchmark.region (r_regionkey);
ENFORCE LOCAL INDEX ON benchmark.supplier (s_suppkey);
ENFORCE LOCAL INDEX ON benchmark.supplier (s_nationkey);
ENFORCE LOCAL INDEX ON benchmark.customer (c_custkey);
ENFORCE LOCAL INDEX ON benchmark.customer (c_nationkey);
ENFORCE LOCAL INDEX ON benchmark.part (p_partkey);
ENFORCE LOCAL INDEX ON benchmark.partsupp (ps_partkey, ps_suppkey);
ENFORCE LOCAL INDEX ON benchmark.partsupp (ps_partkey);
ENFORCE LOCAL INDEX ON benchmark.partsupp (ps_suppkey);
ENFORCE LOCAL INDEX ON benchmark.orders (o_orderkey);
ENFORCE LOCAL INDEX ON benchmark.orders (o_custkey);
COMMIT;
Update database statistics for query optimizer
-- TPC-H Table Analysis Script
-- Analyzes tables and updates statistics for optimal query performance
-- Analyze database to estimate statistics for query optimization
ANALYZE DATABASE ESTIMATE STATISTICS;
COMMIT;
Create 8 TPC-H tables with system-optimized data types
-- TPC-H Table Creation Script
-- Creates all 8 TPC-H tables with appropriate data types and storage options for each database system
-- ClickHouse table creation
-- Nation table
CREATE OR REPLACE TABLE benchmark.nation (
n_nationkey INTEGER NOT NULL,
n_name CHAR(25) NOT NULL,
n_regionkey INTEGER NOT NULL,
n_comment VARCHAR(152)
) ENGINE MergeTree() ORDER BY n_nationkey;
-- Region table
CREATE OR REPLACE TABLE benchmark.region (
r_regionkey INTEGER NOT NULL,
r_name CHAR(25) NOT NULL,
r_comment VARCHAR(152)
) ENGINE MergeTree() ORDER BY r_regionkey;
-- Part table
CREATE OR REPLACE TABLE benchmark.part (
p_partkey INTEGER NOT NULL,
p_name VARCHAR(55) NOT NULL,
p_mfgr CHAR(25) NOT NULL,
p_brand CHAR(10) NOT NULL,
p_type VARCHAR(25) NOT NULL,
p_size INTEGER NOT NULL,
p_container CHAR(10) NOT NULL,
p_retailprice DECIMAL(15,2) NOT NULL,
p_comment VARCHAR(23) NOT NULL
) ENGINE MergeTree() ORDER BY p_partkey;
-- Supplier table
CREATE OR REPLACE TABLE benchmark.supplier (
s_suppkey INTEGER NOT NULL,
s_name CHAR(25) NOT NULL,
s_address VARCHAR(40) NOT NULL,
s_nationkey INTEGER NOT NULL,
s_phone CHAR(15) NOT NULL,
s_acctbal DECIMAL(15,2) NOT NULL,
s_comment VARCHAR(101) NOT NULL
) ENGINE MergeTree() ORDER BY s_suppkey;
-- Partsupp table
CREATE OR REPLACE TABLE benchmark.partsupp (
ps_partkey INTEGER NOT NULL,
ps_suppkey INTEGER NOT NULL,
ps_availqty INTEGER NOT NULL,
ps_supplycost DECIMAL(15,2) NOT NULL,
ps_comment VARCHAR(199) NOT NULL
) ENGINE MergeTree() ORDER BY (ps_partkey, ps_suppkey);
-- Customer table
CREATE OR REPLACE TABLE benchmark.customer (
c_custkey INTEGER NOT NULL,
c_name VARCHAR(25) NOT NULL,
c_address VARCHAR(40) NOT NULL,
c_nationkey INTEGER NOT NULL,
c_phone CHAR(15) NOT NULL,
c_acctbal DECIMAL(15,2) NOT NULL,
c_mktsegment CHAR(10) NOT NULL,
c_comment VARCHAR(117) NOT NULL
) ENGINE MergeTree() ORDER BY (c_mktsegment, c_custkey);
-- Orders table
CREATE OR REPLACE TABLE benchmark.orders (
o_orderkey BIGINT NOT NULL,
o_custkey INTEGER NOT NULL,
o_orderstatus CHAR(1) NOT NULL,
o_totalprice DECIMAL(15,2) NOT NULL,
o_orderdate DATE NOT NULL,
o_orderpriority CHAR(15) NOT NULL,
o_clerk CHAR(15) NOT NULL,
o_shippriority INTEGER NOT NULL,
o_comment VARCHAR(79) NOT NULL
) ENGINE MergeTree() ORDER BY (o_orderdate, o_orderkey);
-- Lineitem table
CREATE OR REPLACE TABLE benchmark.lineitem (
l_orderkey BIGINT NOT NULL,
l_partkey INTEGER NOT NULL,
l_suppkey INTEGER NOT NULL,
l_linenumber INTEGER 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 CHAR(1) NOT NULL,
l_linestatus CHAR(1) NOT NULL,
l_shipdate DATE NOT NULL,
l_commitdate DATE NOT NULL,
l_receiptdate DATE NOT NULL,
l_shipinstruct CHAR(25) NOT NULL,
l_shipmode CHAR(10) NOT NULL,
l_comment VARCHAR(44) NOT NULL
) ENGINE MergeTree() ORDER BY (l_shipdate, l_orderkey, l_partkey);
Create indexes on foreign keys and join columns
-- TPC-H Index Creation Script
-- Creates indexes to optimize query performance for both database systems
-- ClickHouse Skip Indexes: DISABLED for TPC-H Analytical Workload
--
-- Analysis showed that skip indexes cause net performance REGRESSION for TPC-H:
-- - 15/22 queries became slower (1-7% regression)
-- - Only 2/22 queries improved (Q20: -9.5%, Q12: -1.3%)
-- - Overall net negative impact on workload
--
-- Root causes:
-- 1. Redundancy: Many skip indexes duplicate MergeTree primary key (ORDER BY)
-- Example: l_orderkey bloom_filter is redundant with ORDER BY (l_shipdate, l_orderkey, l_partkey)
-- 2. Low selectivity: Indexes on low-cardinality columns (o_orderstatus: 3 values) add overhead
-- 3. Workload mismatch: TPC-H = analytical scans; skip indexes = OLTP point queries
-- 4. Granularity overhead: GRANULARITY 4 adds index maintenance cost without benefit
--
-- Decision: Rely on MergeTree primary keys and OPTIMIZE TABLE compression for best performance
-- For analytical workloads, well-designed ORDER BY clauses are more effective than skip indexes
SELECT 'ClickHouse indexing: Using MergeTree primary keys only (skip indexes disabled for analytical workload)';
Update database statistics for query optimizer
-- TPC-H Table Analysis Script
-- Analyzes tables and updates statistics for optimal query performance
-- ClickHouse Table Optimization
-- Statistics are disabled - using basic optimization only
-- Optimize tables to merge data parts and improve compression
-- OPTIMIZE TABLE FINAL merges all data parts into a single optimized part
-- This improves query performance by reducing the number of parts to scan
OPTIMIZE TABLE benchmark.nation FINAL;
OPTIMIZE TABLE benchmark.region FINAL;
OPTIMIZE TABLE benchmark.part FINAL;
OPTIMIZE TABLE benchmark.supplier FINAL;
OPTIMIZE TABLE benchmark.partsupp FINAL;
OPTIMIZE TABLE benchmark.customer FINAL;
OPTIMIZE TABLE benchmark.orders FINAL;
OPTIMIZE TABLE benchmark.lineitem FINAL;
SELECT 'ClickHouse tables optimized (statistics disabled)';
Create 8 TPC-H tables with system-optimized data types
-- TPC-H Table Creation Script
-- Creates all 8 TPC-H tables with appropriate data types and storage options for each database system
-- ClickHouse table creation
-- Nation table
CREATE OR REPLACE TABLE benchmark.nation (
n_nationkey INTEGER NOT NULL,
n_name CHAR(25) NOT NULL,
n_regionkey INTEGER NOT NULL,
n_comment VARCHAR(152)
) ENGINE MergeTree() ORDER BY n_nationkey;
-- Region table
CREATE OR REPLACE TABLE benchmark.region (
r_regionkey INTEGER NOT NULL,
r_name CHAR(25) NOT NULL,
r_comment VARCHAR(152)
) ENGINE MergeTree() ORDER BY r_regionkey;
-- Part table
CREATE OR REPLACE TABLE benchmark.part (
p_partkey INTEGER NOT NULL,
p_name VARCHAR(55) NOT NULL,
p_mfgr CHAR(25) NOT NULL,
p_brand CHAR(10) NOT NULL,
p_type VARCHAR(25) NOT NULL,
p_size INTEGER NOT NULL,
p_container CHAR(10) NOT NULL,
p_retailprice DECIMAL(15,2) NOT NULL,
p_comment VARCHAR(23) NOT NULL
) ENGINE MergeTree() ORDER BY p_partkey;
-- Supplier table
CREATE OR REPLACE TABLE benchmark.supplier (
s_suppkey INTEGER NOT NULL,
s_name CHAR(25) NOT NULL,
s_address VARCHAR(40) NOT NULL,
s_nationkey INTEGER NOT NULL,
s_phone CHAR(15) NOT NULL,
s_acctbal DECIMAL(15,2) NOT NULL,
s_comment VARCHAR(101) NOT NULL
) ENGINE MergeTree() ORDER BY s_suppkey;
-- Partsupp table
CREATE OR REPLACE TABLE benchmark.partsupp (
ps_partkey INTEGER NOT NULL,
ps_suppkey INTEGER NOT NULL,
ps_availqty INTEGER NOT NULL,
ps_supplycost DECIMAL(15,2) NOT NULL,
ps_comment VARCHAR(199) NOT NULL
) ENGINE MergeTree() ORDER BY (ps_partkey, ps_suppkey);
-- Customer table
CREATE OR REPLACE TABLE benchmark.customer (
c_custkey INTEGER NOT NULL,
c_name VARCHAR(25) NOT NULL,
c_address VARCHAR(40) NOT NULL,
c_nationkey INTEGER NOT NULL,
c_phone CHAR(15) NOT NULL,
c_acctbal DECIMAL(15,2) NOT NULL,
c_mktsegment CHAR(10) NOT NULL,
c_comment VARCHAR(117) NOT NULL
) ENGINE MergeTree() ORDER BY (c_mktsegment, c_custkey);
-- Orders table
CREATE OR REPLACE TABLE benchmark.orders (
o_orderkey BIGINT NOT NULL,
o_custkey INTEGER NOT NULL,
o_orderstatus CHAR(1) NOT NULL,
o_totalprice DECIMAL(15,2) NOT NULL,
o_orderdate DATE NOT NULL,
o_orderpriority CHAR(15) NOT NULL,
o_clerk CHAR(15) NOT NULL,
o_shippriority INTEGER NOT NULL,
o_comment VARCHAR(79) NOT NULL
) ENGINE MergeTree() ORDER BY (o_orderdate, o_orderkey);
-- Lineitem table
CREATE OR REPLACE TABLE benchmark.lineitem (
l_orderkey BIGINT NOT NULL,
l_partkey INTEGER NOT NULL,
l_suppkey INTEGER NOT NULL,
l_linenumber INTEGER 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 CHAR(1) NOT NULL,
l_linestatus CHAR(1) NOT NULL,
l_shipdate DATE NOT NULL,
l_commitdate DATE NOT NULL,
l_receiptdate DATE NOT NULL,
l_shipinstruct CHAR(25) NOT NULL,
l_shipmode CHAR(10) NOT NULL,
l_comment VARCHAR(44) NOT NULL
) ENGINE MergeTree() ORDER BY (l_shipdate, l_orderkey, l_partkey);
Create indexes on foreign keys and join columns
-- TPC-H Index Creation Script
-- Creates indexes to optimize query performance for both database systems
-- ClickHouse Skip Indexes: DISABLED for TPC-H Analytical Workload
--
-- Analysis showed that skip indexes cause net performance REGRESSION for TPC-H:
-- - 15/22 queries became slower (1-7% regression)
-- - Only 2/22 queries improved (Q20: -9.5%, Q12: -1.3%)
-- - Overall net negative impact on workload
--
-- Root causes:
-- 1. Redundancy: Many skip indexes duplicate MergeTree primary key (ORDER BY)
-- Example: l_orderkey bloom_filter is redundant with ORDER BY (l_shipdate, l_orderkey, l_partkey)
-- 2. Low selectivity: Indexes on low-cardinality columns (o_orderstatus: 3 values) add overhead
-- 3. Workload mismatch: TPC-H = analytical scans; skip indexes = OLTP point queries
-- 4. Granularity overhead: GRANULARITY 4 adds index maintenance cost without benefit
--
-- Decision: Rely on MergeTree primary keys and OPTIMIZE TABLE compression for best performance
-- For analytical workloads, well-designed ORDER BY clauses are more effective than skip indexes
SELECT 'ClickHouse indexing: Using MergeTree primary keys only (skip indexes disabled for analytical workload)';
Update database statistics for query optimizer
-- TPC-H Table Analysis Script
-- Analyzes tables and updates statistics for optimal query performance
-- ClickHouse Table Optimization
-- Statistics are disabled - using basic optimization only
-- Optimize tables to merge data parts and improve compression
-- OPTIMIZE TABLE FINAL merges all data parts into a single optimized part
-- This improves query performance by reducing the number of parts to scan
OPTIMIZE TABLE benchmark.nation FINAL;
OPTIMIZE TABLE benchmark.region FINAL;
OPTIMIZE TABLE benchmark.part FINAL;
OPTIMIZE TABLE benchmark.supplier FINAL;
OPTIMIZE TABLE benchmark.partsupp FINAL;
OPTIMIZE TABLE benchmark.customer FINAL;
OPTIMIZE TABLE benchmark.orders FINAL;
OPTIMIZE TABLE benchmark.lineitem FINAL;
SELECT 'ClickHouse tables optimized (statistics disabled)';
Create 8 TPC-H tables with system-optimized data types
-- TPC-H Table Creation Script
-- Creates all 8 TPC-H tables with appropriate data types and storage options for each database system
-- ClickHouse table creation
-- Nation table
CREATE OR REPLACE TABLE benchmark.nation (
n_nationkey INTEGER NOT NULL,
n_name CHAR(25) NOT NULL,
n_regionkey INTEGER NOT NULL,
n_comment VARCHAR(152)
) ENGINE MergeTree() ORDER BY n_nationkey;
-- Region table
CREATE OR REPLACE TABLE benchmark.region (
r_regionkey INTEGER NOT NULL,
r_name CHAR(25) NOT NULL,
r_comment VARCHAR(152)
) ENGINE MergeTree() ORDER BY r_regionkey;
-- Part table
CREATE OR REPLACE TABLE benchmark.part (
p_partkey INTEGER NOT NULL,
p_name VARCHAR(55) NOT NULL,
p_mfgr CHAR(25) NOT NULL,
p_brand CHAR(10) NOT NULL,
p_type VARCHAR(25) NOT NULL,
p_size INTEGER NOT NULL,
p_container CHAR(10) NOT NULL,
p_retailprice DECIMAL(15,2) NOT NULL,
p_comment VARCHAR(23) NOT NULL
) ENGINE MergeTree() ORDER BY p_partkey;
-- Supplier table
CREATE OR REPLACE TABLE benchmark.supplier (
s_suppkey INTEGER NOT NULL,
s_name CHAR(25) NOT NULL,
s_address VARCHAR(40) NOT NULL,
s_nationkey INTEGER NOT NULL,
s_phone CHAR(15) NOT NULL,
s_acctbal DECIMAL(15,2) NOT NULL,
s_comment VARCHAR(101) NOT NULL
) ENGINE MergeTree() ORDER BY s_suppkey;
-- Partsupp table
CREATE OR REPLACE TABLE benchmark.partsupp (
ps_partkey INTEGER NOT NULL,
ps_suppkey INTEGER NOT NULL,
ps_availqty INTEGER NOT NULL,
ps_supplycost DECIMAL(15,2) NOT NULL,
ps_comment VARCHAR(199) NOT NULL
) ENGINE MergeTree() ORDER BY (ps_partkey, ps_suppkey);
-- Customer table
CREATE OR REPLACE TABLE benchmark.customer (
c_custkey INTEGER NOT NULL,
c_name VARCHAR(25) NOT NULL,
c_address VARCHAR(40) NOT NULL,
c_nationkey INTEGER NOT NULL,
c_phone CHAR(15) NOT NULL,
c_acctbal DECIMAL(15,2) NOT NULL,
c_mktsegment CHAR(10) NOT NULL,
c_comment VARCHAR(117) NOT NULL
) ENGINE MergeTree() ORDER BY (c_mktsegment, c_custkey);
-- Orders table
CREATE OR REPLACE TABLE benchmark.orders (
o_orderkey BIGINT NOT NULL,
o_custkey INTEGER NOT NULL,
o_orderstatus CHAR(1) NOT NULL,
o_totalprice DECIMAL(15,2) NOT NULL,
o_orderdate DATE NOT NULL,
o_orderpriority CHAR(15) NOT NULL,
o_clerk CHAR(15) NOT NULL,
o_shippriority INTEGER NOT NULL,
o_comment VARCHAR(79) NOT NULL
) ENGINE MergeTree() ORDER BY (o_orderdate, o_orderkey);
-- Lineitem table
CREATE OR REPLACE TABLE benchmark.lineitem (
l_orderkey BIGINT NOT NULL,
l_partkey INTEGER NOT NULL,
l_suppkey INTEGER NOT NULL,
l_linenumber INTEGER 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 CHAR(1) NOT NULL,
l_linestatus CHAR(1) NOT NULL,
l_shipdate DATE NOT NULL,
l_commitdate DATE NOT NULL,
l_receiptdate DATE NOT NULL,
l_shipinstruct CHAR(25) NOT NULL,
l_shipmode CHAR(10) NOT NULL,
l_comment VARCHAR(44) NOT NULL
) ENGINE MergeTree() ORDER BY (l_shipdate, l_orderkey, l_partkey);
Create indexes on foreign keys and join columns
-- TPC-H Index Creation Script
-- Creates indexes to optimize query performance for both database systems
-- ClickHouse Skip Indexes: DISABLED for TPC-H Analytical Workload
--
-- Analysis showed that skip indexes cause net performance REGRESSION for TPC-H:
-- - 15/22 queries became slower (1-7% regression)
-- - Only 2/22 queries improved (Q20: -9.5%, Q12: -1.3%)
-- - Overall net negative impact on workload
--
-- Root causes:
-- 1. Redundancy: Many skip indexes duplicate MergeTree primary key (ORDER BY)
-- Example: l_orderkey bloom_filter is redundant with ORDER BY (l_shipdate, l_orderkey, l_partkey)
-- 2. Low selectivity: Indexes on low-cardinality columns (o_orderstatus: 3 values) add overhead
-- 3. Workload mismatch: TPC-H = analytical scans; skip indexes = OLTP point queries
-- 4. Granularity overhead: GRANULARITY 4 adds index maintenance cost without benefit
--
-- Decision: Rely on MergeTree primary keys and OPTIMIZE TABLE compression for best performance
-- For analytical workloads, well-designed ORDER BY clauses are more effective than skip indexes
SELECT 'ClickHouse indexing: Using MergeTree primary keys only (skip indexes disabled for analytical workload)';
Update database statistics for query optimizer
-- TPC-H Table Analysis Script
-- Analyzes tables and updates statistics for optimal query performance
-- ClickHouse Table Optimization
-- Statistics are enabled - collect statistics for query optimizer (ClickHouse 24.6+)
-- Statistics help the query optimizer make better join order decisions
-- Add statistics for join optimization (most critical columns)
-- Lineitem: Most critical table for complex queries
ALTER TABLE benchmark.lineitem ADD STATISTICS IF NOT EXISTS l_orderkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.lineitem ADD STATISTICS IF NOT EXISTS l_partkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.lineitem ADD STATISTICS IF NOT EXISTS l_suppkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.lineitem ADD STATISTICS IF NOT EXISTS l_quantity TYPE countmin, tdigest;
ALTER TABLE benchmark.lineitem ADD STATISTICS IF NOT EXISTS l_receiptdate TYPE countmin;
ALTER TABLE benchmark.lineitem ADD STATISTICS IF NOT EXISTS l_commitdate TYPE countmin;
-- Orders: Critical for joins
ALTER TABLE benchmark.orders ADD STATISTICS IF NOT EXISTS o_orderkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.orders ADD STATISTICS IF NOT EXISTS o_custkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.orders ADD STATISTICS IF NOT EXISTS o_orderdate TYPE countmin, tdigest;
ALTER TABLE benchmark.orders ADD STATISTICS IF NOT EXISTS o_orderstatus TYPE countmin, uniq;
-- Part: Used in filtered joins
ALTER TABLE benchmark.part ADD STATISTICS IF NOT EXISTS p_partkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.part ADD STATISTICS IF NOT EXISTS p_type TYPE countmin, uniq;
ALTER TABLE benchmark.part ADD STATISTICS IF NOT EXISTS p_brand TYPE countmin, uniq;
ALTER TABLE benchmark.part ADD STATISTICS IF NOT EXISTS p_container TYPE countmin, uniq;
-- Supplier: Join and filter columns
ALTER TABLE benchmark.supplier ADD STATISTICS IF NOT EXISTS s_suppkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.supplier ADD STATISTICS IF NOT EXISTS s_nationkey TYPE countmin, tdigest, uniq;
-- Customer: Join columns
ALTER TABLE benchmark.customer ADD STATISTICS IF NOT EXISTS c_custkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.customer ADD STATISTICS IF NOT EXISTS c_nationkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.customer ADD STATISTICS IF NOT EXISTS c_mktsegment TYPE countmin, uniq;
-- Partsupp: Join columns
ALTER TABLE benchmark.partsupp ADD STATISTICS IF NOT EXISTS ps_partkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.partsupp ADD STATISTICS IF NOT EXISTS ps_suppkey TYPE countmin, tdigest, uniq;
-- Nation: Small table but frequently joined
ALTER TABLE benchmark.nation ADD STATISTICS IF NOT EXISTS n_nationkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.nation ADD STATISTICS IF NOT EXISTS n_name TYPE countmin, uniq;
ALTER TABLE benchmark.nation ADD STATISTICS IF NOT EXISTS n_regionkey TYPE countmin, tdigest, uniq;
-- Region: Small table
ALTER TABLE benchmark.region ADD STATISTICS IF NOT EXISTS r_regionkey TYPE countmin, tdigest, uniq;
ALTER TABLE benchmark.region ADD STATISTICS IF NOT EXISTS r_name TYPE countmin, uniq;
-- Materialize statistics
ALTER TABLE benchmark.lineitem MATERIALIZE STATISTICS l_orderkey, l_partkey, l_suppkey, l_quantity, l_receiptdate, l_commitdate;
ALTER TABLE benchmark.orders MATERIALIZE STATISTICS o_orderkey, o_custkey, o_orderdate, o_orderstatus;
ALTER TABLE benchmark.part MATERIALIZE STATISTICS p_partkey, p_type, p_brand, p_container;
ALTER TABLE benchmark.supplier MATERIALIZE STATISTICS s_suppkey, s_nationkey;
ALTER TABLE benchmark.customer MATERIALIZE STATISTICS c_custkey, c_nationkey, c_mktsegment;
ALTER TABLE benchmark.partsupp MATERIALIZE STATISTICS ps_partkey, ps_suppkey;
ALTER TABLE benchmark.nation MATERIALIZE STATISTICS n_nationkey, n_name, n_regionkey;
ALTER TABLE benchmark.region MATERIALIZE STATISTICS r_regionkey, r_name;
-- Optimize tables to merge data parts and improve compression
-- OPTIMIZE TABLE FINAL merges all data parts into a single optimized part
-- This improves query performance by reducing the number of parts to scan
OPTIMIZE TABLE benchmark.nation FINAL;
OPTIMIZE TABLE benchmark.region FINAL;
OPTIMIZE TABLE benchmark.part FINAL;
OPTIMIZE TABLE benchmark.supplier FINAL;
OPTIMIZE TABLE benchmark.partsupp FINAL;
OPTIMIZE TABLE benchmark.customer FINAL;
OPTIMIZE TABLE benchmark.orders FINAL;
OPTIMIZE TABLE benchmark.lineitem FINAL;
SELECT 'ClickHouse statistics collected and tables optimized';
| query | system | warmup | runs | median_ms | mean_ms | std_ms | min_ms | max_ms |
|---|---|---|---|---|---|---|---|---|
| Q01 | clickhouse | 2,482.60 | 7 | 2,462.00 | 2,466.20 | 11.90 | 2,456.10 | 2,491.70 |
| Q01 | clickhouse_tuned | 2,540.80 | 7 | 2,640.60 | 2,654.90 | 74.80 | 2,551.80 | 2,739.10 |
| Q01 | exasol | 802.30 | 7 | 801.10 | 800.10 | 4.60 | 794.70 | 806.60 |
| Q02 | clickhouse | 1,241.40 | 7 | 1,052.70 | 1,066.90 | 36.10 | 1,039.00 | 1,144.40 |
| Q02 | clickhouse_tuned | 1,353.00 | 7 | 1,120.50 | 1,121.60 | 26.50 | 1,088.50 | 1,172.00 |
| Q02 | exasol | 93.70 | 7 | 78.80 | 78.80 | 2.40 | 75.20 | 82.10 |
| Q03 | clickhouse | 4,117.10 | 7 | 3,986.50 | 3,981.10 | 20.80 | 3,953.80 | 4,017.30 |
| Q03 | clickhouse_tuned | 4,507.20 | 7 | 4,446.60 | 4,424.50 | 104.70 | 4,310.30 | 4,613.50 |
| Q03 | exasol | 341.80 | 7 | 346.50 | 344.90 | 5.00 | 339.40 | 353.00 |
| Q04 | clickhouse | 3,293.60 | 7 | 2,547.90 | 2,583.80 | 95.20 | 2,517.30 | 2,792.10 |
| Q04 | clickhouse_tuned | 16,957.00 | 7 | 14,560.70 | 14,683.20 | 272.30 | 14,433.40 | 15,122.60 |
| Q04 | exasol | 64.70 | 7 | 63.20 | 63.40 | 0.40 | 62.90 | 64.00 |
| Q05 | clickhouse | 9,505.40 | 7 | 8,776.70 | 8,751.00 | 115.00 | 8,590.80 | 8,923.60 |
| Q05 | clickhouse_tuned | 9,433.20 | 7 | 9,282.50 | 9,191.10 | 403.50 | 8,309.80 | 9,537.20 |
| Q05 | exasol | 273.40 | 7 | 208.90 | 209.30 | 1.30 | 207.70 | 211.80 |
| Q06 | clickhouse | 940.20 | 7 | 163.10 | 164.30 | 2.60 | 161.80 | 167.90 |
| Q06 | clickhouse_tuned | 1,050.50 | 7 | 170.00 | 171.20 | 4.20 | 166.70 | 179.30 |
| Q06 | exasol | 43.80 | 7 | 43.70 | 43.60 | 0.30 | 43.20 | 43.90 |
| Q07 | clickhouse | 6,372.70 | 7 | 4,886.40 | 4,882.50 | 23.00 | 4,849.50 | 4,915.30 |
| Q07 | clickhouse_tuned | 6,436.70 | 7 | 5,042.20 | 5,054.30 | 38.40 | 5,011.70 | 5,116.40 |
| Q07 | exasol | 276.00 | 7 | 288.60 | 286.10 | 11.30 | 273.20 | 303.40 |
| Q08 | clickhouse | 7,063.30 | 7 | 7,765.60 | 7,734.80 | 249.10 | 7,213.60 | 7,979.80 |
| Q08 | clickhouse_tuned | 7,309.40 | 7 | 8,082.30 | 8,094.10 | 84.00 | 8,006.00 | 8,226.20 |
| Q08 | exasol | 80.20 | 7 | 76.40 | 79.50 | 8.90 | 75.30 | 99.60 |
| Q09 | clickhouse | 13,474.30 | 7 | 11,756.10 | 11,904.00 | 293.80 | 11,645.60 | 12,456.10 |
| Q09 | clickhouse_tuned | 14,229.40 | 7 | 11,956.30 | 12,014.10 | 214.10 | 11,816.00 | 12,414.90 |
| Q09 | exasol | 965.20 | 7 | 960.60 | 962.40 | 3.50 | 959.40 | 968.30 |
| Q10 | clickhouse | 4,175.60 | 7 | 2,846.60 | 2,937.90 | 163.20 | 2,801.90 | 3,179.00 |
| Q10 | clickhouse_tuned | 4,312.20 | 7 | 2,895.40 | 3,084.20 | 349.10 | 2,831.30 | 3,642.10 |
| Q10 | exasol | 570.50 | 7 | 573.00 | 574.60 | 6.20 | 565.20 | 585.00 |
| Q11 | clickhouse | 884.70 | 7 | 617.10 | 615.90 | 12.10 | 599.00 | 629.70 |
| Q11 | clickhouse_tuned | 1,176.20 | 7 | 744.80 | 743.50 | 24.20 | 707.60 | 774.00 |
| Q11 | exasol | 152.70 | 7 | 150.00 | 151.20 | 7.00 | 144.30 | 165.00 |
| Q12 | clickhouse | 2,277.10 | 7 | 749.40 | 759.70 | 25.20 | 736.10 | 811.40 |
| Q12 | clickhouse_tuned | 2,734.60 | 7 | 881.80 | 895.30 | 46.10 | 856.00 | 987.10 |
| Q12 | exasol | 88.10 | 7 | 85.30 | 85.20 | 0.50 | 84.60 | 85.70 |
| Q13 | clickhouse | 5,018.20 | 7 | 4,735.00 | 4,750.90 | 83.50 | 4,668.90 | 4,912.80 |
| Q13 | clickhouse_tuned | 5,910.10 | 7 | 5,423.10 | 5,465.00 | 108.90 | 5,350.90 | 5,662.70 |
| Q13 | exasol | 682.50 | 7 | 675.40 | 675.60 | 7.90 | 664.30 | 690.50 |
| Q14 | clickhouse | 201.10 | 7 | 213.10 | 211.60 | 5.30 | 201.40 | 216.70 |
| Q14 | clickhouse_tuned | 238.30 | 7 | 230.40 | 231.70 | 3.60 | 227.80 | 237.20 |
| Q14 | exasol | 82.70 | 7 | 82.70 | 82.80 | 0.30 | 82.40 | 83.40 |
| Q15 | clickhouse | 335.20 | 7 | 280.50 | 289.50 | 16.50 | 277.40 | 322.70 |
| Q15 | clickhouse_tuned | 414.80 | 7 | 367.10 | 371.60 | 23.60 | 352.30 | 419.70 |
| Q15 | exasol | 389.40 | 7 | 380.90 | 380.70 | 4.40 | 373.70 | 386.10 |
| Q16 | clickhouse | 458.10 | 7 | 450.50 | 449.80 | 3.90 | 445.10 | 454.80 |
| Q16 | clickhouse_tuned | 760.60 | 7 | 691.50 | 690.30 | 19.30 | 669.20 | 728.60 |
| Q16 | exasol | 470.70 | 7 | 486.10 | 485.50 | 4.40 | 479.60 | 492.80 |
| Q17 | clickhouse | 6,053.90 | 7 | 5,394.80 | 5,396.30 | 21.10 | 5,366.90 | 5,425.60 |
| Q17 | clickhouse_tuned | 1,461.10 | 7 | 1,317.40 | 1,320.00 | 11.90 | 1,307.50 | 1,343.00 |
| Q17 | exasol | 31.00 | 7 | 30.90 | 31.00 | 0.20 | 30.80 | 31.40 |
| Q18 | clickhouse | 5,538.00 | 7 | 5,354.30 | 5,369.80 | 55.80 | 5,330.40 | 5,490.90 |
| Q18 | clickhouse_tuned | 15,523.80 | 7 | 13,314.80 | 13,608.10 | 594.90 | 12,974.50 | 14,455.80 |
| Q18 | exasol | 649.50 | 7 | 639.40 | 638.50 | 8.30 | 626.60 | 648.10 |
| Q19 | clickhouse | 2,260.10 | 7 | 2,190.90 | 2,190.90 | 11.40 | 2,176.90 | 2,205.10 |
| Q19 | clickhouse_tuned | 7,027.40 | 7 | 5,623.40 | 5,641.50 | 68.80 | 5,538.50 | 5,744.10 |
| Q19 | exasol | 27.10 | 7 | 27.00 | 27.10 | 0.40 | 26.50 | 27.60 |
| Q20 | clickhouse | 378.50 | 7 | 345.50 | 345.20 | 4.70 | 340.00 | 354.20 |
| Q20 | clickhouse_tuned | 3,288.40 | 7 | 2,660.60 | 2,637.50 | 62.80 | 2,532.60 | 2,701.80 |
| Q20 | exasol | 286.90 | 7 | 281.20 | 281.40 | 1.90 | 278.40 | 283.70 |
| Q21 | clickhouse | 46,792.60 | 7 | 46,498.20 | 46,517.80 | 463.00 | 45,952.20 | 47,354.70 |
| Q21 | clickhouse_tuned | 33,517.20 | 7 | 33,190.90 | 33,276.70 | 2,162.90 | 30,555.80 | 36,986.60 |
| Q21 | exasol | 390.10 | 7 | 384.70 | 389.80 | 10.90 | 383.10 | 413.40 |
| Q22 | clickhouse | 616.30 | 7 | 609.00 | 613.50 | 23.10 | 586.50 | 647.70 |
| Q22 | clickhouse_tuned | 2,335.70 | 7 | 632.50 | 651.40 | 95.30 | 548.50 | 766.40 |
| Q22 | exasol | 96.40 | 7 | 95.60 | 95.60 | 0.30 | 95.00 | 96.00 |
The following table shows the time taken to provision cloud instances and install database software:
| System | Instance Provisioning | Software Installation | Total Setup Time |
|---|---|---|---|
| Clickhouse | 126.77s | 28.59s | 155.36s |
| Clickhouse_tuned | 126.77s | 29.10s | 155.87s |
| Clickhouse_stat | 126.77s | 29.80s | 156.57s |
| Exasol | 126.77s | 538.85s | 665.62s |
Infrastructure Provisioning: 126.77s
Cloud instances were provisioned (VMs created, networking configured)
Software Installation Comparison:
# Create GPT partition table
sudo parted /dev/nvme1n1 mklabel gpt
# Execute sudo command on remote system
sudo parted -s /dev/nvme1n1 mklabel gpt
# Create 132GB partition for data generation
sudo parted /dev/nvme1n1 mkpart primary ext4 1MiB 132GiB
# Execute sudo command on remote system
sudo parted -s /dev/nvme1n1 mkpart primary ext4 1MiB 132GiB
# Create raw partition for Exasol (1637GB)
sudo parted /dev/nvme1n1 mkpart primary 132GiB 100%
# Execute sudo command on remote system
sudo parted -s /dev/nvme1n1 mkpart primary 132GiB 100%
# Format /dev/nvme1n1p1 with ext4 filesystem
sudo mkfs.ext4 -F /dev/nvme1n1p1
# Create mount point /data/tpch_gen
sudo mkdir -p /data/tpch_gen
# Mount /dev/nvme1n1p1 to /data/tpch_gen
sudo mount /dev/nvme1n1p1 /data/tpch_gen
# Set ownership of /data/tpch_gen to $(whoami):$(whoami)
sudo chown -R $(whoami):$(whoami) /data/tpch_gen
# Create Exasol system user
sudo useradd -m exasol
# Add exasol user to sudo group
sudo usermod -aG sudo exasol
# Set password for exasol user (interactive)
sudo passwd exasol
# Download c4 cluster management tool v4.28.2
wget https://x-up.s3.amazonaws.com/releases/c4/linux/x86_64/4.28.2/c4 -O c4 && chmod +x c4
# Generate SSH key pair for cluster communication
ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -N ""
# Create c4 configuration file on remote system
cat > /tmp/exasol_c4.conf << 'EOF'
CCC_HOST_ADDRS="<PRIVATE_IP>"
CCC_HOST_EXTERNAL_ADDRS="<PUBLIC_IP>"
CCC_HOST_DATADISK=/dev/nvme1n1p2
CCC_HOST_IMAGE_USER=exasol
CCC_HOST_IMAGE_PASSWORD=<EXASOL_IMAGE_PASSWORD>
CCC_HOST_KEY_PAIR_FILE=id_rsa
CCC_PLAY_RESERVE_NODES=0
CCC_PLAY_WORKING_COPY=@exasol-2025.1.0
CCC_PLAY_DB_PASSWORD=<EXASOL_DB_PASSWORD>
CCC_PLAY_ADMIN_PASSWORD=<EXASOL_ADMIN_PASSWORD>
CCC_ADMINUI_START_SERVER=true
EOF
# Deploy Exasol cluster using c4
./c4 host play -i /tmp/exasol_c4.conf
# Get cluster play ID for confd_client operations
c4 ps
# Install Exasol license file
confd_client license_upload license: <LICENSE_CONTENT>
# Stop Exasol database for parameter configuration
confd_client db_stop db_name: Exasol
# Configure Exasol database parameters for analytical workload optimization
confd_client db_configure db_name: Exasol params_add: "['-writeTouchInit=1','-cacheMonitorLimit=0','-maxOverallSlbUsageRatio=0.95','-useQueryCache=0','-query_log_timeout=0','-joinOrderMethod=0','-etlCheckCertsDefault=0']"
# Starting database with new parameters
confd_client db_start db_name: Exasol
dbram: 220goptimizer_mode: analytical-writeTouchInit=1-cacheMonitorLimit=0-maxOverallSlbUsageRatio=0.95-useQueryCache=0-query_log_timeout=0-joinOrderMethod=0-etlCheckCertsDefault=0None
# Format /dev/nvme1n1 with ext4 filesystem
sudo mkfs.ext4 -F /dev/nvme1n1
# Create mount point /data
sudo mkdir -p /data
# Mount /dev/nvme1n1 to /data
sudo mount /dev/nvme1n1 /data
# Set ownership of /data to ubuntu:ubuntu
sudo chown -R ubuntu:ubuntu /data
# Create ClickHouse data directory under /data
sudo mkdir -p /data/clickhouse
# Set ownership of /data/clickhouse to clickhouse:clickhouse
sudo chown -R clickhouse:clickhouse /data/clickhouse
# Update package lists
sudo apt-get update
# Install prerequisite packages for secure repository access
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
# Add ClickHouse GPG key to system keyring
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
# Add ClickHouse official repository to APT sources
ARCH=$(dpkg --print-architecture) && echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg arch=${ARCH}] https://packages.clickhouse.com/deb stable main" | sudo tee /etc/apt/sources.list.d/clickhouse.list
# Update package lists with ClickHouse repository
sudo apt-get update
# Install ClickHouse server and client version <PUBLIC_IP>
sudo apt-get install -y clickhouse-server=25.9.4.58 clickhouse-client=25.9.4.58
# Create custom ClickHouse configuration file
sudo tee /etc/clickhouse-server/config.d/benchmark.xml > /dev/null << 'EOF'
<clickhouse>
<listen_host>::</listen_host>
<path>/data/clickhouse</path>
<tmp_path>/data/clickhouse/tmp</tmp_path>
<max_server_memory_usage>212792564121</max_server_memory_usage>
<max_concurrent_queries>16</max_concurrent_queries>
<background_pool_size>32</background_pool_size>
<background_schedule_pool_size>32</background_schedule_pool_size>
<max_table_size_to_drop>50000000000</max_table_size_to_drop>
</clickhouse>
EOF
# Configure ClickHouse user profile with password and query settings
sudo tee /etc/clickhouse-server/users.d/benchmark.xml > /dev/null << 'EOF'
<clickhouse>
<users>
<default replace="true">
<password_sha256_hex>2cca9d8714615f4132390a3db9296d39ec051b3faff87be7ea5f7fe0e2de14c9</password_sha256_hex>
<networks>
<ip>::/0</ip>
</networks>
</default>
</users>
<profiles>
<default>
<max_threads>32</max_threads>
<max_memory_usage>200000000000</max_memory_usage>
<max_bytes_before_external_sort>100000000000</max_bytes_before_external_sort>
<max_bytes_before_external_group_by>100000000000</max_bytes_before_external_group_by>
<join_use_nulls>1</join_use_nulls>
<allow_experimental_correlated_subqueries>1</allow_experimental_correlated_subqueries>
<optimize_read_in_order>1</optimize_read_in_order>
<max_insert_threads>8</max_insert_threads>
</default>
</profiles>
</clickhouse>
EOF
# Start ClickHouse server service
sudo systemctl start clickhouse-server
# Enable ClickHouse server to start on boot
sudo systemctl enable clickhouse-server
memory_limit: 230gmax_threads: 32max_memory_usage: 200.0GB/data/clickhouse
# Format /dev/nvme1n1 with ext4 filesystem
sudo mkfs.ext4 -F /dev/nvme1n1
# Create mount point /data
sudo mkdir -p /data
# Mount /dev/nvme1n1 to /data
sudo mount /dev/nvme1n1 /data
# Set ownership of /data to ubuntu:ubuntu
sudo chown -R ubuntu:ubuntu /data
# Create ClickHouse data directory under /data
sudo mkdir -p /data/clickhouse
# Set ownership of /data/clickhouse to clickhouse:clickhouse
sudo chown -R clickhouse:clickhouse /data/clickhouse
# Update package lists
sudo apt-get update
# Install prerequisite packages for secure repository access
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
# Add ClickHouse GPG key to system keyring
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
# Add ClickHouse official repository to APT sources
ARCH=$(dpkg --print-architecture) && echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg arch=${ARCH}] https://packages.clickhouse.com/deb stable main" | sudo tee /etc/apt/sources.list.d/clickhouse.list
# Update package lists with ClickHouse repository
sudo apt-get update
# Install ClickHouse server and client version <PUBLIC_IP>
sudo apt-get install -y clickhouse-server=25.9.4.58 clickhouse-client=25.9.4.58
# Create custom ClickHouse configuration file
sudo tee /etc/clickhouse-server/config.d/benchmark.xml > /dev/null << 'EOF'
<clickhouse>
<listen_host>::</listen_host>
<path>/data/clickhouse</path>
<tmp_path>/data/clickhouse/tmp</tmp_path>
<max_server_memory_usage>212792564121</max_server_memory_usage>
<max_concurrent_queries>16</max_concurrent_queries>
<background_pool_size>32</background_pool_size>
<background_schedule_pool_size>32</background_schedule_pool_size>
<max_table_size_to_drop>50000000000</max_table_size_to_drop>
</clickhouse>
EOF
# Configure ClickHouse user profile with password and query settings
sudo tee /etc/clickhouse-server/users.d/benchmark.xml > /dev/null << 'EOF'
<clickhouse>
<users>
<default replace="true">
<password_sha256_hex>2cca9d8714615f4132390a3db9296d39ec051b3faff87be7ea5f7fe0e2de14c9</password_sha256_hex>
<networks>
<ip>::/0</ip>
</networks>
</default>
</users>
<profiles>
<default>
<max_threads>32</max_threads>
<max_memory_usage>200000000000</max_memory_usage>
<max_bytes_before_external_sort>100000000000</max_bytes_before_external_sort>
<max_bytes_before_external_group_by>100000000000</max_bytes_before_external_group_by>
<join_use_nulls>1</join_use_nulls>
<allow_experimental_correlated_subqueries>1</allow_experimental_correlated_subqueries>
<optimize_read_in_order>1</optimize_read_in_order>
<max_insert_threads>8</max_insert_threads>
</default>
</profiles>
</clickhouse>
EOF
# Start ClickHouse server service
sudo systemctl start clickhouse-server
# Enable ClickHouse server to start on boot
sudo systemctl enable clickhouse-server
memory_limit: 230gmax_threads: 32max_memory_usage: 200.0GB/data/clickhouse
# Format /dev/nvme1n1 with ext4 filesystem
sudo mkfs.ext4 -F /dev/nvme1n1
# Create mount point /data
sudo mkdir -p /data
# Mount /dev/nvme1n1 to /data
sudo mount /dev/nvme1n1 /data
# Set ownership of /data to ubuntu:ubuntu
sudo chown -R ubuntu:ubuntu /data
# Create ClickHouse data directory under /data
sudo mkdir -p /data/clickhouse
# Set ownership of /data/clickhouse to clickhouse:clickhouse
sudo chown -R clickhouse:clickhouse /data/clickhouse
# Update package lists
sudo apt-get update
# Install prerequisite packages for secure repository access
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
# Add ClickHouse GPG key to system keyring
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
# Add ClickHouse official repository to APT sources
ARCH=$(dpkg --print-architecture) && echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg arch=${ARCH}] https://packages.clickhouse.com/deb stable main" | sudo tee /etc/apt/sources.list.d/clickhouse.list
# Update package lists with ClickHouse repository
sudo apt-get update
# Install ClickHouse server and client version <PUBLIC_IP>
sudo apt-get install -y clickhouse-server=25.9.4.58 clickhouse-client=25.9.4.58
# Create custom ClickHouse configuration file
sudo tee /etc/clickhouse-server/config.d/benchmark.xml > /dev/null << 'EOF'
<clickhouse>
<listen_host>::</listen_host>
<path>/data/clickhouse</path>
<tmp_path>/data/clickhouse/tmp</tmp_path>
<max_server_memory_usage>212792570675</max_server_memory_usage>
<max_concurrent_queries>16</max_concurrent_queries>
<background_pool_size>32</background_pool_size>
<background_schedule_pool_size>32</background_schedule_pool_size>
<max_table_size_to_drop>50000000000</max_table_size_to_drop>
</clickhouse>
EOF
# Configure ClickHouse user profile with password and query settings
sudo tee /etc/clickhouse-server/users.d/benchmark.xml > /dev/null << 'EOF'
<clickhouse>
<users>
<default replace="true">
<password_sha256_hex>2cca9d8714615f4132390a3db9296d39ec051b3faff87be7ea5f7fe0e2de14c9</password_sha256_hex>
<networks>
<ip>::/0</ip>
</networks>
</default>
</users>
<profiles>
<default>
<max_threads>32</max_threads>
<max_memory_usage>200000000000</max_memory_usage>
<max_bytes_before_external_sort>100000000000</max_bytes_before_external_sort>
<max_bytes_before_external_group_by>100000000000</max_bytes_before_external_group_by>
<join_use_nulls>1</join_use_nulls>
<allow_experimental_correlated_subqueries>1</allow_experimental_correlated_subqueries>
<optimize_read_in_order>1</optimize_read_in_order>
<max_insert_threads>8</max_insert_threads>
<allow_experimental_statistics>1</allow_experimental_statistics>
<allow_statistics_optimize>1</allow_statistics_optimize>
</default>
</profiles>
</clickhouse>
EOF
# Start ClickHouse server service
sudo systemctl start clickhouse-server
# Enable ClickHouse server to start on boot
sudo systemctl enable clickhouse-server
memory_limit: 230gmax_threads: 32max_memory_usage: 200.0GB/data/clickhouse