TDengine TSDB Query Engine Optimization Guide

Juno Qiu

July 5, 2026 /

TDengine’s Query Engine uses a distributed computing architecture. The core components include the client driver (taosc), virtual storage nodes (vnode), and query compute nodes (qnode). The taosc handles SQL parsing and execution plan generation, the vnode performs local data scanning and filtering, and the qnode handles cross-node aggregation, sorting, and merge computations. After a query is submitted, six phases execute in sequence: SQL parsing, metadata retrieval, execution plan generation, task distribution, parallel execution, and result aggregation.

Six-layer filtering mechanism

TDengine applies six filtering layers to minimize the data that reaches computation:

  1. Metadata filtering. The Tag index on Supertables quickly locates target Subtables, excluding irrelevant ones before any data scan.
  2. Block filtering. Each data block stores min/max statistics. Blocks whose entire value range falls outside the query condition are skipped.
  3. Intra-block filtering. Within a block, columnar storage segments that do not satisfy the condition are skipped.
  4. Row filtering. The WHERE condition is applied row by row on the remaining data.
  5. Tag secondary filtering. After data retrieval, Tag conditions are applied again to ensure precision.
  6. Result filtering. The HAVING clause is applied to the final aggregated result set.

Time and tag filtering optimization

The PARTITION BY syntax supports grouping and aggregation by any Tag or expression, enabling per-device or per-group analytics without manual iteration.

SLIMIT and SOFFSET control the number of Subtables included in results, avoiding full scans across all tables when only a subset is needed.

Multi-level aggregation and downsampling

TDengine supports a rich set of aggregate functions and downsampling strategies. The FILL clause handles gaps in time-series data with multiple strategies: NULL, PREV, NEXT, LINEAR, and VALUE.

Window query types

Five window types are available for partitioning time-series data:

  • Time Window (INTERVAL). Divides data into fixed-duration intervals. Supports sliding windows via the SLIDING parameter.
  • State Window (STATE_WINDOW). Groups consecutive rows where a state expression evaluates to a specific value, useful for equipment operating-mode analysis.
  • Session Window (SESSION). Opens a new window when the gap between consecutive timestamps exceeds a threshold (for example, 10 minutes), identifying discrete activity sessions.
  • Event Window (EVENT_WINDOW). Defines windows bounded by start and end conditions (for example, temperature exceeding 80 as start, dropping below 40 as end).
  • Count Window (COUNT_WINDOW). Creates a window for every fixed number of rows (for example, every 100 records).

Join queries

ASOF Join. For each row in the left table, finds the row in the right table whose timestamp is closest to but not later than the left row’s timestamp. This is especially useful for correlating events with the nearest preceding state.

Window Join. Associates data from multiple sources within a specified time window, defined by WINDOW_OFFSET relative to the primary key timestamp.

Parallel execution strategies

TDengine supports four execution plan strategies:

  1. All vnode local execution. Suitable for edge computing scenarios where all data resides on local vnodes.
  2. Intelligent scheduling (recommended). The system selects an appropriate distribution of work between vnodes and qnodes.
  3. Storage-compute separation. Designed for large-scale analytical workloads with dedicated compute resources.
  4. Qnode priority. Optimized for analytical clusters where qnodes handle the majority of computation.

Supertable aggregation

Tags are kept in memory with efficient index structures, while time-series data is stored in time-partitioned files. Three advantages emerge from this design: millisecond Tag filtering, physical data isolation by device, and automatic query routing to the correct vnodes.

Query caching mechanisms

  • Metadata cache. Supertable schemas and Tag indexes remain in memory for fast access.
  • Latest data cache. The LAST(*) function returns in milliseconds by reading from the read cache.
  • Data block cache. Frequently accessed data blocks stay in memory, with hit rates typically reaching 90% or higher.

Query performance optimization practices

  • Prefer Tag filtering. Tag conditions resolve to specific Subtables before any data scan begins.
  • Always bound the time range. Unbounded time ranges force full table scans. Specify the narrowest time window the query requires.
  • Use SLIMIT judiciously. When only the top N devices are needed, SLIMIT prevents scanning all Subtables.
  • Match window granularity to business needs. A 1-second INTERVAL on multi-year data generates excessive windows. Choose a granularity that aligns with the analytical purpose.
  • Pair downsampling with FILL. Downsampled results often contain gaps. Apply an appropriate FILL strategy for complete output.
  • Configure queryPolicy per scenario. Select the execution plan strategy that matches the deployment topology.