background-shape
Time Series for IIoT, Timescale and InfluxDB Compared
August 14, 2024 · 6 min read · by Muhammad Amal programming

TL;DR — Pick TimescaleDB 2.16 when you need joins, transactions and SQL for industrial context. Pick InfluxDB 3.x when you need columnar speed on pure metrics and you’re happy with Flux or SQL through IOx.

The “which time-series DB” question is the second most common one I get after “which broker”, and the answer is again less religious than people expect. TimescaleDB 2.16 and InfluxDB 3.x are both excellent in 2024. They’ve converged on a lot, diverged on a few important things, and the right choice depends on what else lives next to your telemetry.

I’ve shipped both. I run Timescale for industrial workloads where telemetry sits next to relational data like asset hierarchies, work orders and quality records. I run Influx where the workload is pure metrics, high cardinality is a real concern, and the queries are dashboards rather than analytical joins. This post walks through how I’d decide for a 2024 IIoT project.

A quick framing. Both databases will happily ingest your data. The hard parts of running a time-series store for IIoT are schema, retention, downsampling, and how your application queries it. Pick a database after you’ve thought about those.

The Schema Question

In TimescaleDB, the natural schema for IIoT telemetry is wide-or-narrow, and the answer is usually narrow. One row per (device, metric, timestamp), with a small dimensions table joined for context.

CREATE TABLE telemetry (
    ts          timestamptz NOT NULL,
    device_id   bigint NOT NULL,
    metric_id   smallint NOT NULL,
    value       double precision NOT NULL,
    quality     smallint NOT NULL DEFAULT 192
);
SELECT create_hypertable('telemetry', 'ts',
    chunk_time_interval => INTERVAL '6 hours');
CREATE INDEX ON telemetry (device_id, metric_id, ts DESC);
ALTER TABLE telemetry SET (
    timescaledb.compress,
    timescaledb.compress_segmentby = 'device_id, metric_id',
    timescaledb.compress_orderby = 'ts DESC'
);
SELECT add_compression_policy('telemetry', INTERVAL '7 days');

Six-hour chunks, segment-by on the device and metric, compress after a week. This is a workhorse pattern. On NVMe, with proper compression, you’ll see 10–20x compression ratios on typical industrial telemetry.

In InfluxDB 3.x, you don’t manage the schema this way. You write line protocol with measurement, tags and fields, and the engine handles storage in Parquet via IOx. The mental model is closer to “log it and query it later”, which is great when you don’t know in advance what dimensions you’ll need.

temperature,plant=jkt1,line=3,device=temp1 value=72.4 1723632000000000000

Tags become indexed dimensions. Fields are the actual measurements. The 3.x engine is genuinely fast and handles unbounded cardinality much better than 1.x did, which used to be the major operational headache.

Ingestion Patterns

For Timescale, the right ingestion is batched COPY from your stream processor. A single COPY of 10–50k rows is the sweet spot. INSERTs row by row will pin your write throughput at maybe 10k rows per second per connection, which is fine for small fleets but limiting for anything serious.

A Go ingester writing from Kafka into Timescale, using pgx:

batch := &pgx.Batch{}
for _, row := range rows {
    batch.Queue(
        "INSERT INTO telemetry (ts, device_id, metric_id, value, quality) VALUES ($1,$2,$3,$4,$5)",
        row.Ts, row.DeviceID, row.MetricID, row.Value, row.Quality,
    )
}
br := db.SendBatch(ctx, batch)
defer br.Close()
for range rows {
    if _, err := br.Exec(); err != nil { return err }
}

SendBatch pipelines the inserts on a single connection. For higher throughput, COPY FROM is faster still and worth the extra code.

For Influx 3.x, the v2 client over HTTP with batched line protocol is standard. The server-side commit is fast and the v3 ingestion path is much more forgiving on bursty writes than 1.x ever was.

Querying

This is where the two diverge most. Timescale queries are SQL, which means anything that can connect to Postgres works. Grafana, Metabase, Superset, your application’s existing ORM. Continuous aggregates let you pre-materialize rollups:

CREATE MATERIALIZED VIEW telemetry_1m
WITH (timescaledb.continuous) AS
SELECT
    time_bucket('1 minute', ts) AS bucket,
    device_id, metric_id,
    avg(value) AS avg_v, max(value) AS max_v, min(value) AS min_v,
    count(*) AS n
FROM telemetry
GROUP BY bucket, device_id, metric_id;

SELECT add_continuous_aggregate_policy('telemetry_1m',
    start_offset => INTERVAL '2 hours',
    end_offset   => INTERVAL '5 minutes',
    schedule_interval => INTERVAL '1 minute');

The continuous aggregate refreshes incrementally, and SELECT against the original hypertable transparently uses the rollup when the query range allows. This single feature is what makes Timescale feel like a database rather than a time-series store.

Influx 3.x supports SQL through Flight SQL in addition to Flux. SQL support in 3.x is genuinely good and a clear improvement over the 1.x InfluxQL story. For dashboarding workloads, both databases hit similar performance with proper rollups.

Cardinality

For industrial workloads, cardinality is usually moderate. Tens of thousands of devices, tens to a few hundred metrics each. Total series count in the millions, not billions. Both databases handle that fine.

If you’re in a domain with truly unbounded cardinality, vehicle telemetry, smart meter rollouts, consumer device fleets, Influx 3.x with IOx is the safer bet. The columnar Parquet storage genuinely doesn’t care about cardinality the way 1.x did.

For typical industrial work, cardinality is a non-issue and the schema and query story matter more.

Retention and Tiered Storage

Both databases support retention policies. Timescale has retention policies on hypertables, and a tiered storage feature (in Timescale Cloud, and via add-ons on self-hosted) that moves old chunks to S3-compatible object storage. Influx 3.x persists to Parquet on object storage natively, with a hot cache.

For self-hosted Timescale, my standard policy is. Raw data for 30 days. Continuous aggregates at 1-minute resolution for 1 year. Continuous aggregates at 1-hour resolution forever. Anything older than 30 days exported to Parquet on S3 and queried via DuckDB when needed.

SELECT add_retention_policy('telemetry', INTERVAL '30 days');

That’s the entire retention policy. Continuous aggregates have their own retention.

Cost Notes

For self-hosted, both databases are similar in TCO. Timescale needs Postgres expertise on the team, which most teams already have. Influx 3.x OSS needs Influx-specific expertise, which is a smaller pool. Managed offerings are competitive. Timescale Cloud and InfluxDB Cloud both have free tiers for small workloads and predictable pricing past that.

The hidden cost in either case is the rollup discipline. If you don’t downsample, your storage will grow linearly with retention and your queries will get slower. Both databases give you the tools. You have to use them.

Common Pitfalls

  • No compression policy on Timescale. The default is no compression. Uncompressed industrial telemetry will eat disk shockingly fast. Add the policy on day one.
  • Wide tables with sparse metrics. Tempting in Timescale, painful at query time. Stay narrow.
  • Tag cardinality explosion in Influx. 3.x handles it but the bill still scales. Don’t put high-cardinality identifiers like UUIDs in tags.
  • Querying raw at dashboard resolution. If a dashboard panel needs 1-minute data over 30 days, query the 1-minute continuous aggregate, not the raw hypertable.
  • No backups of rollups. Continuous aggregates are derived but expensive to recompute on a fresh restore. Back them up with the rest of the database.

Wrapping Up

Both Timescale and Influx are good in 2024. For most industrial deployments, where telemetry needs to join against context and the team knows SQL, I lean Timescale. For high-cardinality metric workloads or teams already running Influx, 3.x is a real improvement and a fine choice.

If you haven’t seen the upstream of this data flow, the IIoT reference architecture and scaling MQTT brokers posts cover where these databases sit. The TimescaleDB hypertable documentation is the canonical reference for the chunking model.

Pick the one your team will operate well. The data won’t care.