
By Tiger Data Team
Updated at Jun 12, 2026
A 100-vehicle fleet reporting GPS position and 10 OBD-II signals at 1 Hz generates roughly 4 million data points per hour. Scale that to 1,000 vehicles and you're at 40 million per hour - roughly 950 million rows per day. The database architecture you choose for your fleet platform determines whether dashboard queries complete in milliseconds or minutes at that scale, and whether you can run driver behavior analytics at all.
This page covers what fleet telemetry data actually looks like, why it's a time-series workload, why general-purpose databases struggle at fleet scale, and how to choose and design a database architecture that handles it. Tiger Data builds Tiger Cloud, one of the databases compared below. The goal is to give you enough context to evaluate the options - including cases where Tiger Cloud is not the right fit.
Fleet telemetry is the continuous collection and transmission of sensor and event data from vehicles to a central system. Each vehicle reports its position, speed, engine state, and fault codes in real time, producing a timestamped, append-only stream of readings that accumulates at millions of rows per day across a modern fleet.
This is distinct from "fleet management software" - the application layer built on top. This page is about the database behind it.
A modern connected vehicle fleet produces four primary data types:
Location data. GPS pings (latitude, longitude, altitude, heading) at 1- to 30-second intervals per vehicle. High frequency, moderate size per record.
OBD-II diagnostics. Vehicle speed, engine RPM, throttle position, fuel level, engine coolant temperature, fault codes. Available on every vehicle built after 1996. Typically sampled at 1 Hz during operation.
CAN bus messages. Raw ECU signals: brake pressure, steering angle, transmission state, airbag sensors, wheel speed per axle. Available on vehicles with CAN logger hardware (a telematics gateway or dedicated data logger). Message rates vary by bus - from a few hundred frames per second on low-speed CAN to several thousand on high-speed CAN.
Driver behavior events. Hard braking, rapid acceleration, sharp cornering, idle time. Either derived on-device from accelerometer data or computed server-side from raw OBD-II streams.
EV fleets add a second layer on top of these: battery management system (BMS) signals. These include state of charge (SoC), state of health (SoH), cell temperature by module, and charge session events. SoH changes slowly - over weeks and months - but requires high-frequency historical data to compute accurately. SoC changes continuously during driving and charging.
All of this data shares two structural characteristics that define how it should be stored:
Every record is timestamped at collection. Data is append-only - historical readings don't change. Analytical queries are almost always time-range bounded ("show me this vehicle's speed for the last 4 hours"). That's the time-series profile.
The second characteristic is cardinality. vehicle_id is a high-cardinality dimension. A fleet of 10,000 vehicles means 10,000 distinct time series flowing into the same table simultaneously. How a database handles that cardinality determines whether it scales or falls over.
This isn't an argument that general-purpose databases are bad - they're not. The architecture question matters at hundreds of vehicles and above. A small fleet under 50 vehicles at low sample frequency may run fine on standard PostgreSQL without any extensions.
At scale, three problems compound:
Sequential scan growth. A 100-vehicle fleet at 1 Hz generates ~95M rows per day. Without time-based partitioning, a 30-day query must touch all 30 days of data - even if you only need one. Query cost grows linearly with history. There's no shortcut without explicit partitioning.
Index bloat on high-cardinality dimensions. Indexing (vehicle_id, time) in a general-purpose RDBMS creates write amplification at high vehicle counts. Each vehicle writes to the same shared index structure. As cardinality grows, so does the overhead of maintaining that index.
Storage inefficiency on redundant readings. A vehicle parked for eight hours sends many near-identical readings. Standard row storage retains every value at full fidelity. Time-series engines use delta-of-delta encoding on sorted time columns - a parked vehicle's readings compress dramatically because the differences between consecutive values are near-zero. Compression ratios of 90-98% are typical on real fleet data.
Aggregation cost at dashboard query time. Fleet dashboards need "average speed per vehicle per hour" or "total idle time per driver per day." Without pre-computed aggregates, every dashboard load rescans the raw table. A fleet operations dashboard with 50 concurrent users rescans it 50 times, simultaneously.
A time-series database addresses all four of these with its core architecture: time-based partitioning, columnar compression, and incremental materialized views.
Four architectural approaches are worth understanding before looking at specific products:
Time-series database. Purpose-built for timestamped, high-cardinality, append-only data. Usually the right fit for fleet telemetry backends. The partitioning, compression, and aggregation primitives are built in.
General-purpose RDBMS. Works for small fleets or mixed workloads where fleet telemetry is one of several use cases. Struggles at high vehicle counts without explicit partitioning and extension support.
Document store. MongoDB is sometimes chosen for flexible schema. The tradeoff: no SQL join capability for vehicle metadata, and no native time-partitioning or geospatial integration at the level PostGIS provides.
Event streaming platform. Kafka and Kinesis handle the ingestion layer well but are not query engines. They always need a downstream storage database. Treating Kafka as "the database" is a common early mistake.
For the databases most commonly evaluated for fleet telemetry backends:
Database | SQL support | Geospatial | High-cardinality handling | Continuous aggregates | Managed service |
Tiger Cloud (TimescaleDB) | Full PostgreSQL SQL | PostGIS (native extension) | Hypertable + columnar compression | Yes, incremental | Yes - Tiger Cloud |
InfluxDB 3.x | SQL + InfluxQL | Non-native | Columnar engine (v3 removes the tag-cardinality limits of earlier versions) | No (requires external aggregation job) | Yes - Cloud Serverless / Dedicated |
QuestDB | SQL dialect | Geohash-based (limited vs. PostGIS) | Designed for high-cardinality; row-based storage | No | Limited |
TDengine | SQL-like (TAOS) | Limited | Supertable model, optimized for many time series | Yes, but proprietary dialect | Yes |
MongoDB | No SQL | GeoJSON + 2dsphere index | Document model; no time partitioning | No | Yes - Atlas |
InfluxDB's most-cited fleet deployment pairs it with Neo4J - one database for time-series telemetry, a second for vehicle relationship graphs. Tiger Data's answer to that pattern is a single PostgreSQL instance: hypertables for telemetry, standard relational tables for vehicle metadata, and PostGIS for geospatial analytics, with no ETL between systems.
One practical note on InfluxDB: version fragmentation is a real operational risk. InfluxDB 1.x, 2.x, 3.0, Cloud Serverless, and Cloud Dedicated have meaningfully different APIs, retention policy models, and query languages. Teams inheriting an existing InfluxDB fleet setup should verify which version they're on before making architectural decisions.
For teams evaluating IoT database options more broadly, see the IoT database comparison and IIoT database requirements guides for a fuller picture.
Most database comparison articles describe options. This section shows the Data Definition Language (DDL).
The fundamental schema decision for vehicle telemetry is whether to model signals as rows or columns:
Narrow-row model. One row per (time, vehicle_id, signal_name, value). Adding a new signal type requires no migration - just start inserting rows with a new signal value. High row volume, flexible schema. Recommended for heterogeneous fleets where vehicle types differ in their OBD-II signal sets.
Wide-row model. One row per (time, vehicle_id) with a column for each signal (speed, rpm, fuel_level, lat, lon, ...). Fewer rows, easier to query for known signal sets. Schema migrations required when signals are added. Better suited for uniform fleets with a stable, fixed signal set.
For most new builds, start with the narrow-row model. The flexibility to add signals without a migration is worth the higher row count.
The examples below use TimescaleDB syntax, which powers Tiger Cloud.
-- Vehicle metadata (standard relational table)
CREATE TABLE vehicles (
vehicle_id TEXT PRIMARY KEY,
make TEXT,
model TEXT,
year INT,
vin TEXT UNIQUE,
fuel_type TEXT, -- 'ICE', 'BEV', 'PHEV', 'HEV'
fleet_group TEXT
);
-- Telemetry fact table (time-series, Hypercore columnstore enabled)
CREATE TABLE vehicle_telemetry (
time TIMESTAMPTZ NOT NULL,
vehicle_id TEXT NOT NULL REFERENCES vehicles(vehicle_id),
signal TEXT NOT NULL, -- 'speed_mph', 'rpm', 'fuel_pct', 'soc_pct', etc.
value DOUBLE PRECISION NOT NULL
) WITH (
tsdb.hypertable,
tsdb.segmentby = 'vehicle_id, signal',
tsdb.orderby = 'time DESC'
);The tsdb.segmentby = 'vehicle_id, signal' setting groups each vehicle's readings for each signal into the same columnstore segment. Queries filtering by vehicle_id can skip entire segments that don't match, keeping per-vehicle queries fast as the table grows. The columnstore policy is created automatically - older chunks are compressed to the columnstore in the background, typically achieving 90–98% storage savings.
GPS data deserves its own table because the PostGIS GEOMETRY column type enables spatial indexing that a plain DOUBLE PRECISION lat/lon pair does not:
-- GPS trajectory table
CREATE TABLE vehicle_location (
time TIMESTAMPTZ NOT NULL,
vehicle_id TEXT NOT NULL,
position GEOMETRY(Point, 4326) -- WGS84 (standard GPS)
);
SELECT create_hypertable('vehicle_location', by_range('time'));
CREATE INDEX ON vehicle_location USING GIST (position);Pre-computing driver behavior metrics avoids rescanning the raw telemetry table on every dashboard load:
CREATE MATERIALIZED VIEW vehicle_daily_summary
WITH (timescaledb.continuous) AS
SELECT
time_bucket('1 day', time) AS day,
vehicle_id,
MAX(value) FILTER (WHERE signal = 'speed_mph') AS max_speed_mph,
AVG(value) FILTER (WHERE signal = 'speed_mph') AS avg_speed_mph,
SUM(value) FILTER (WHERE signal = 'idle_seconds') AS total_idle_seconds
FROM vehicle_telemetry
GROUP BY day, vehicle_id
WITH NO DATA;
SELECT add_continuous_aggregate_policy('vehicle_daily_summary',
start_offset => INTERVAL '3 days',
end_offset => INTERVAL '1 hour',
schedule_interval => INTERVAL '1 hour'
);The continuous aggregate refreshes incrementally - it only reprocesses chunks that changed since the last refresh, not the entire history. For a 1,000-vehicle fleet, the daily rollup query that previously rescanned ~950 million rows now reads from a pre-computed summary table.
For the full continuous aggregates documentation, see docs.timescale.com/use-timescale/latest/continuous-aggregates/.
Fleet analytics regularly require spatial queries: "show me all vehicles within 5 km of this depot" or "flag vehicles that entered a restricted geofence." These need spatial indexing - a lat/lon column pair doesn't give you that.
PostGIS runs inside the same PostgreSQL instance as the telemetry hypertables. Here's a geofence detection query:
-- Find vehicles that entered a geofence in the last hour
SELECT DISTINCT vehicle_id
FROM vehicle_location
WHERE time > NOW() - INTERVAL '1 hour'
AND ST_Within(
position,
ST_Buffer(
ST_SetSRID(ST_MakePoint(-87.6298, 41.8781), 4326),
0.05 -- ~5 km radius in degrees (approximate)
)
);Because the vehicle_location hypertable is in the same PostgreSQL instance as the vehicles metadata table, you can join geospatial results to vehicle ownership data, fleet group assignments, or driver records in a single query. No ETL, no separate geo database, no JOIN across network boundaries.
For the full PostGIS feature set with Tiger Data, see the PostGIS with Tiger Data for geospatial time-series queries guide.
Understanding where data originates helps you design the ingestion path correctly.
Each vehicle runs a Telematics Control Unit (TCU) - a device that reads OBD-II or CAN bus data, combines it with GPS, buffers locally, and transmits to the central backend. Common protocols are MQTT over cellular, HTTP REST, or proprietary binary formats.
Three ingestion paths to Tiger Cloud are common in production:
MQTT pipeline. The TCU publishes to an MQTT broker (Mosquitto, HiveMQ, EMQX). Telegraf or a custom consumer subscribes and writes to Tiger Cloud. Best fit for fleets with existing MQTT infrastructure or constrained bandwidth where connection overhead matters. See the MQTT to PostgreSQL ingestion pipeline guide for implementation details.
Direct HTTP/REST. The TCU sends batched payloads directly to an application layer (the fleet platform API), which writes to Tiger Cloud. Lower per-message protocol overhead than MQTT. Suitable when the fleet platform owns the ingestion layer.
Kafka / Kinesis / Pub/Sub. An event streaming bus as the ingestion layer, with Tiger Cloud as the downstream storage database. The open-source fleet-telemetry project (github.com/teslamotors/fleet-telemetry) supports Kafka, Kinesis, and Pub/Sub as dispatch backends but explicitly leaves storage to the implementer. Tiger Cloud is a compatible storage target via any of those backends.
One architectural requirement that's easy to miss: TCUs buffer data locally when cellular connectivity drops (tunnels, rural routes, loading docks). When connectivity resumes, they flush, which means out-of-order writes are normal. The hypertable approach handles late-arriving data correctly because each row carries its own timestamp. There's no assumption that insert order equals event order.
For teams managing local storage on the TCU itself, see the edge database sync patterns guide.
EV fleets add battery management system (BMS) data on top of the base GPS and OBD-II signals. The write pattern is different: BMS data streams at higher frequency during fast-charging (sub-second updates are possible during DC fast charge) and lower frequency when the vehicle is idle.
The BMS signals that differ from ICE OBD-II:
State of charge (SoC) - percentage of usable capacity remaining. Changes continuously during driving and charging.
State of health (SoH) - long-term capacity degradation. Changes slowly but requires years of high-frequency history to compute accurately.
Cell temperature by module - lithium packs have dozens to hundreds of cells; thermal management systems monitor temperature per module or cell group.
Charge session events - start time, stop time, energy delivered, peak charging rate. These are discrete events, not continuous telemetry.
In the narrow-row schema above, all of these are just additional signal values: soc_pct, soh_pct, cell_temp_c_module_3, etc. No schema migration is required to add them.
For teams building OCPP-based charging networks alongside fleet tracking, see the EV charging management system database architecture guide.
No single database is right for every fleet. Here's a decision framework based on the criteria that actually differentiate options at fleet scale.
Choose Tiger Cloud if:
Your fleet platform already runs on PostgreSQL, or you want one database for telemetry, relational vehicle metadata, and geospatial queries without ETL between them
You need SQL joins between telemetry and vehicle master data
You need geofencing or trajectory analysis without a separate spatial database (PostGIS runs natively in the same instance)
You want continuous aggregates for driver behavior metrics without a scheduled batch job
You want managed infrastructure (Tiger Cloud) with the option to self-host on TimescaleDB (the open-source project) if needed
Choose InfluxDB if:
Your team is already invested in the InfluxDB ecosystem (Telegraf, Flux, Chronograf) and migration cost outweighs the architectural benefits of SQL
You are on InfluxDB 3.x Cloud Dedicated and the workload is pure time-series with no relational joins required
Note: InfluxDB version fragmentation (1.x vs. 2.x vs. 3.0 APIs) is a real operational risk for teams inheriting existing deployments
Choose QuestDB if:
The primary workload is bulk ingestion and fast time-range queries with no geospatial or join requirements
You are comfortable with a smaller ecosystem and fewer managed service options
Choose TDengine if:
The fleet is very large (millions of vehicles), the team is comfortable with a non-SQL query dialect, and the Chinese enterprise support model fits the organization
Don't use Tiger Data if:
The primary workload is graph-based - complex vehicle-to-vehicle relationship queries or route optimization graphs. A dedicated graph database handles that pattern better.
The team's existing stack is deeply invested in InfluxDB 1.x with no migration budget. At small fleet sizes, the switching cost may not justify the architectural change.
For broader IoT workload context, the time-series databases compared page covers more options across more dimensions.
Ready to build your fleet telemetry backend? Start a Tiger Cloud trial or explore the TimescaleDB documentation for self-hosted deployment.
For most teams building a fleet telemetry backend from scratch, a time-series database is the right starting point. The data is timestamped, append-only, and query patterns are almost always time-range bounded. Tiger Cloud (PostgreSQL extended with TimescaleDB) is a strong default if the team wants SQL, geospatial queries via PostGIS, and relational joins to vehicle metadata in a single database. InfluxDB is a reasonable choice for teams already in that ecosystem; be aware of version fragmentation and the absence of native geospatial support.
It depends on fleet size, geospatial requirements, and SQL investment. Tiger Cloud handles geospatial and time-series in one database via PostGIS. InfluxDB is purpose-built for time-series but requires a separate geo layer for spatial queries. QuestDB has strong ingestion throughput but a limited ecosystem. TDengine is designed for very large fleets with its own proprietary tooling. The right answer depends on your specific requirements.
Model GPS as a PostGIS geometry column in a hypertable to enable spatial indexing. Model OBD-II signals in a narrow-row schema: (time, vehicle_id, signal_name, value). This keeps the schema flexible - adding a new signal type requires no migration. Time-partition the table by week or month depending on fleet size. Compression is handled automatically by the columnstore policy; older chunks are moved to columnar storage in the background.
Standard PostgreSQL without time-series extensions struggles above a few hundred vehicles at 1 Hz, due to sequential scan growth and index bloat on high-cardinality (vehicle_id, time) indexes. TimescaleDB adds time-based partitioning (hypertables), columnar compression via Hypercore, and continuous aggregates that directly address these bottlenecks. Tiger Cloud is Tiger Data's managed service running this stack.
CAN bus data is high-frequency, high-cardinality sensor data - the narrow-row schema handles CAN signals the same way as OBD-II signals. EV battery BMS data (SoC, SoH, cell temperature) is also handled as additional signal types in the same schema. For CAN-based fleets, the storage database choice matters less than the hardware logger choice - the narrow-row schema accepts whatever signals the logger produces.
PostGIS with Tiger Data enables spatial queries directly on telemetry data: ST_Within for geofencing, ST_Distance for proximity, ST_MakeLine for trajectory construction. These run in the same PostgreSQL instance as the time-series hypertables, so a single query can filter by time range and spatial boundary simultaneously, without ETL.
The fleet-telemetry open-source project (github.com/teslamotors/fleet-telemetry) handles dispatch to Kafka, Kinesis, Pub/Sub, and MQTT but explicitly does not specify a storage layer. The storage decision is left to the implementer. Tiger Cloud is a compatible storage target via any of those dispatch backends.
The standard approach is a hypertable partitioned by time with vehicle_id and signal as the segment keys for compression. Two tables: vehicle_telemetry (narrow-row: time, vehicle_id, signal, value) and vehicle_location (time, vehicle_id, PostGIS geometry). A vehicles table holds relational metadata. Continuous aggregates pre-compute hourly and daily driver behavior metrics. TimescaleDB is the open-source project; Tiger Cloud is the managed service running the same engine.