QuestDB Platform
QuestDB is a high-performance open-source time-series database optimized for fast ingestion and SQL queries. It supports the PostgreSQL wire protocol (port 8812) for query execution and a REST API (port 9000) for efficient bulk data import. BenchBox connects via psycopg 3 over the PG wire protocol and uses the REST API /imp endpoint for high-throughput CSV ingestion. SQL translation targets the postgres dialect via SQLGlot.
QuestDB is designed for time-series and event-driven workloads, with features like designated timestamps, automatic partitioning by time, and the SYMBOL type for low-cardinality string columns. It delivers competitive ingestion throughput against InfluxDB, TimescaleDB, and ClickHouse on time-series workloads.
Features
- PostgreSQL wire protocol - Standard PG wire protocol via psycopg 3 (port 8812)
- REST API CSV import - High-throughput bulk data loading via
/impendpoint (port 9000) - Full TPC-H support - All 22 queries with row count validation
- PostgreSQL dialect - SQL translation via SQLGlot
postgresdialect - Time-series optimized - Designated timestamps, partitioning by time, SYMBOL type
- Autocommit mode - PG wire protocol operates in autocommit mode (required by QuestDB)
- TPC file normalization - Automatic handling of pipe-delimited
.tblfiles with trailing delimiter removal - Chunked parquet loading - Large parquet inputs are streamed through
/impas CSV chunks, withparquet_chunk_rowscontrolling the row budget per request - TLS support - Optional HTTPS for REST API endpoints via the adapter
use_tlsparameter
Quick Start
The commands install the QuestDB extra (which provides the psycopg 3 driver), configure the connection (QuestDB must be
running), and run the TPC-H benchmark.
uv add benchbox --extra questdb
export QUESTDB_HOST=localhost
benchbox run --platform questdb --benchmark tpch --scale 0.01Docker Quick Start
The commands start QuestDB with Docker (all ports exposed), verify PG wire protocol connectivity, verify the REST API, and run the benchmark.
docker run -p 9000:9000 -p 8812:8812 -p 9009:9009 -p 9003:9003 \ questdb/questdb:latest
psql -h 127.0.0.1 -p 8812 -U admin -d qdb -c "SELECT 1"
curl http://localhost:9000/exec?query=SELECT%201
benchbox run --platform questdb --benchmark tpch --scale 0.01QuestDB Ports
| Port | Protocol | Purpose |
|---|---|---|
| 9000 | HTTP | REST API for CSV import (/imp) and queries (/exec) |
| 8812 | TCP | PostgreSQL wire protocol for SQL queries |
| 9009 | TCP | InfluxDB Line Protocol (ILP) for high-throughput ingestion |
| 9003 | HTTP | Health check and metrics endpoint |
Configuration Options
CLI options are passed as --platform-option KEY=VALUE.
| Option | CLI | Environment Variable | Default | Description |
|---|---|---|---|---|
host | yes | QUESTDB_HOST | localhost | QuestDB server hostname |
pg_port | yes | QUESTDB_PG_PORT | 8812 | PostgreSQL wire protocol port |
http_port | yes | QUESTDB_HTTP_PORT | 9000 | REST API HTTP port |
ilp_port | yes | - | 9009 | InfluxDB Line Protocol port |
username | yes | - | admin | QuestDB username |
password | yes | - | quest | QuestDB password |
database | yes | - | qdb | QuestDB database name |
loading_method | yes | - | rest | Loading method: rest (CSV import) or ilp |
use_tls | no | - | false | Use HTTPS for REST API endpoints |
connect_timeout | no | - | 10 | Connection timeout in seconds |
parquet_chunk_rows | no | - | 200000 | Rows per parquet batch when streaming wide tables through /imp |
Options marked “no” are adapter constructor parameters; the benchbox run CLI
does not accept them.
Data Loading
BenchBox loads data into QuestDB using the REST API /imp endpoint for bulk CSV import. For parquet inputs, the adapter converts each pyarrow batch into CSV and streams it through /imp; there is no COPY FROM STDIN fallback in the current adapter.
Loading Process
- Schema creation - Tables are created via PG wire protocol with QuestDB-compatible DDL
- Foreign key removal - FK constraints are stripped (QuestDB does not support foreign keys)
- DROP TABLE adaptation -
IF EXISTSis added to DROP TABLE statements for idempotent schema creation - TPC file normalization - Pipe-delimited
.tblfiles are streamed through a normalizer that removes trailing delimiters - REST API import - CSV data is uploaded to the
/impendpoint with table name, delimiter, durability settings, andforceHeader=truefor chunked parquet uploads - Chunk sizing for wide parquet tables - the adapter
parquet_chunk_rowsparameter lowers the number of rows per/imprequest when a denormalized parquet file would otherwise exceed QuestDB’s HTTP receive budget
REST API Import (/imp)
The primary data loading mechanism uses QuestDB’s REST API:
- Endpoint:
http://<host>:<http_port>/imp - Method: HTTP POST with multipart file upload
- Parameters:
name(table),delimiter,overwrite,durableandforceHeader=truefor chunked parquet uploads - Format: CSV with configurable delimiter (auto-detected for TPC
.tblfiles) - Throughput: Significantly higher than row-by-row INSERT for bulk datasets
- Wide parquet tuning: lower
parquet_chunk_rowsto 50000 or less when a very wide table would make each CSV chunk too large for a single HTTP request
InfluxDB Line Protocol (ILP)
QuestDB also supports the InfluxDB Line Protocol on port 9009 for high-throughput time-series ingestion. While BenchBox uses the REST API for benchmark data loading, ILP is available for custom ingestion workflows:
- Port: 9009 (TCP)
- Protocol: InfluxDB Line Protocol
- Throughput: Millions of rows per second for time-series data
- Use case: Real-time streaming ingestion
Usage Examples
Basic Benchmarks
The commands run TPC-H at scale factor 0.01 (a quick test), at scale factor 1, and for specific queries only.
benchbox run --platform questdb --benchmark tpch --scale 0.01
benchbox run --platform questdb --benchmark tpch --scale 1.0
benchbox run --platform questdb --benchmark tpch --queries Q1,Q6,Q17Environment Variable Configuration
export QUESTDB_HOST=questdb.example.comexport QUESTDB_PG_PORT=8812export QUESTDB_HTTP_PORT=9000
benchbox run --platform questdb --benchmark tpch --scale 1.0CLI Option Configuration
benchbox run --platform questdb --benchmark tpch --scale 1.0 \ --platform-option host=questdb.example.com \ --platform-option pg_port=8812 \ --platform-option http_port=9000 \ --platform-option username=admin \ --platform-option password=questLine Protocol Loading
benchbox run --platform questdb --benchmark tpch --scale 1.0 \ --platform-option host=questdb.example.com \ --platform-option loading_method=ilpDry Run (Preview)
This previews the execution plan without running it.
benchbox run --platform questdb --benchmark tpch --scale 1.0 --dry-run ./previewArchitecture
Adapter Structure
The QuestDB adapter is a single-module adapter:
| Module | Class | Responsibility |
|---|---|---|
questdb.py | QuestDBAdapter | Connection, schema, loading, query execution |
Connection Model
BenchBox CLI | vQuestDBAdapter | +-- PG Wire Protocol (psycopg 3) --> QuestDB (port 8812) | - Schema DDL (CREATE TABLE, DROP TABLE) | - Query execution (SELECT, EXPLAIN) | - Autocommit mode required | +-- REST API (requests) --> QuestDB (port 9000) - /imp endpoint for bulk CSV import - Chunked parquet → CSV uploads via /imp - /exec endpoint for row count verification - Optional TLS (HTTPS) supportPlatform Information
At runtime, BenchBox captures platform metadata:
{ "platform_type": "questdb", "platform_name": "QuestDB", "host": "localhost", "pg_port": 8812, "http_port": 9000, "dialect": "postgres", "configuration": { "database": "qdb" }, "version": "7.x.x"}Single Database Model
QuestDB uses a single database per instance. The adapter sets skip_database_management = True because:
- There is no
CREATE DATABASEorDROP DATABASEsupport - The
databaseparameter (default:qdb) identifies the instance, not a user-created database check_database_exists()tests connectivity rather than database presence
Time-Series Considerations
Designated Timestamps
QuestDB tables can have a designated timestamp column that enables time-based partitioning and optimized time-range queries:
CREATE TABLE sensor_data ( timestamp TIMESTAMP, device_id SYMBOL, temperature DOUBLE, humidity DOUBLE) TIMESTAMP(timestamp) PARTITION BY DAY;While TPC-H tables do not use designated timestamps, the adapter supports them for custom benchmarks and time-series workloads.
Partitioning
QuestDB supports automatic time-based partitioning:
PARTITION BY NONE- No partitioning (default)PARTITION BY HOUR- Hourly partitionsPARTITION BY DAY- Daily partitionsPARTITION BY MONTH- Monthly partitionsPARTITION BY YEAR- Yearly partitions
Partitioning is specified at table creation time and cannot be changed after the fact.
SYMBOL Type
QuestDB’s SYMBOL type is optimized for low-cardinality string columns (e.g., status codes, country codes, device IDs). SYMBOLs are stored as integers internally with a symbol table for deduplication, providing significant storage and query performance benefits over VARCHAR for repeated string values.
Constraints
QuestDB has a minimal constraint model:
- No foreign keys - The adapter automatically strips FK constraints from DDL
- No traditional primary keys - Uniqueness is not enforced at the database level
- No ALTER TABLE ADD CONSTRAINT - Constraints must be defined at table creation time
Troubleshooting
Connection Refused
Error: Failed to connect to QuestDBSolutions:
- Verify QuestDB is running and accessible on the configured host
- Check that port 8812 (PG wire protocol) is open and not blocked by a firewall
- For Docker deployments, ensure port mapping is correct (
-p 8812:8812) - Test connectivity directly:
psql -h <host> -p 8812 -U admin -d qdb -c "SELECT 1"
Missing psycopg Dependency
Error: Missing dependencies for questdb platform: psycopgSolutions:
- Install the QuestDB extra:
uv add benchbox --extra questdb - Or install the driver directly:
uv add "psycopg[binary]"
REST API Import Failures
Error: REST API import failedSolutions:
- Verify the REST API is accessible on the HTTP port (default: 9000)
- Check that
requestsis installed:uv add requests - Test the REST API directly:
curl http://<host>:9000/exec?query=SELECT%201 - Lower the adapter
parquet_chunk_rowsparameter for very wide parquet tables - If using TLS, ensure the adapter
use_tlsparameter is set and certificates are valid
Schema Creation Failures
Error: critical CREATE TABLE statement(s) failedSolutions:
- Check QuestDB server logs for detailed error messages
- Verify the QuestDB user has sufficient privileges
- Ensure sufficient disk space on the QuestDB server
- Review the translated DDL for QuestDB-incompatible syntax (e.g., unsupported column types)
Autocommit Mode Errors
QuestDB requires autocommit mode on the PG wire protocol. The adapter sets conn.autocommit = True automatically. If you encounter transaction-related errors:
- Ensure you are not wrapping queries in explicit
BEGIN/COMMITblocks - QuestDB does not support multi-statement transactions via PG wire protocol
Slow Data Loading
Solutions:
- Ensure the REST API port (9000) is accessible for bulk CSV import
- If falling back to COPY, check network latency between BenchBox host and QuestDB
- For large datasets, consider increasing the QuestDB server’s memory allocation
- Check disk I/O on the QuestDB server during loading
See Also
- Platform Comparison Matrix - Compare all platforms
- Platform Selection Guide - Choosing the right platform
- TPC-H Benchmark - TPC-H benchmark guide
- TPC-DS Benchmark - TPC-DS benchmark guide
- Deployment Modes Guide - Platform deployment architecture