DuckDB provides a set of metrics that can be used to monitor the performance and health of the database.
Metrics are named group.metric, e.g., query.total_time or operator.timing.
The set of collected metrics is controlled with the tracked_metrics setting, which takes a list of glob patterns, e.g., ['query.*', 'operator.timing'].
By default, all metrics are collected (['*']).
The available metrics, along with their types and units, can be listed with the duckdb_available_metrics() table function:
SELECT metric_name, metric_type, unit
FROM duckdb_available_metrics();
All Metrics
The metrics are organized into the following groups:
query Metrics
Metrics measured over the entire query.
| Name | Type | Unit | Description |
|---|---|---|---|
query.cpu_time |
double |
seconds | CPU time spent on the query |
query.sql |
string |
The SQL string of the query | |
query.total_intermediate_rows |
uint64 |
rows | Cumulative number of intermediate rows produced by the query |
query.total_intermediate_size_bytes |
uint64 |
bytes | Cumulative size in bytes of all intermediate results produced by the query |
query.total_row_groups_scanned |
uint64 |
row_groups | Cumulative number of row groups scanned by the query |
query.total_row_groups_to_scan |
uint64 |
row_groups | Cumulative total number of row groups available to scan |
query.total_rows_scanned |
uint64 |
rows | Cumulative number of rows scanned by the query |
query.total_time |
double |
seconds | Time spent executing the entire query |
system Metrics
Metrics on system resources, such as memory and threads, used while running the query.
| Name | Type | Unit | Description |
|---|---|---|---|
system.blocked_thread_time |
double |
seconds | Time spent waiting for a thread to become available |
system.peak_buffer_memory |
uint64 |
bytes | Peak memory usage of the buffer manager |
system.peak_streaming_buffer_size |
uint64 |
bytes | Peak number of bytes a streaming query result held: queued bytes plus the units blocked workers hold, both exact. Units still under construction are not counted |
system.peak_temp_dir_size |
uint64 |
bytes | Peak size of the temporary directory |
system.total_memory_allocated |
uint64 |
bytes | The total memory allocated by the buffer manager |
io Metrics
Metrics on the data read from and written to storage.
| Name | Type | Unit | Description |
|---|---|---|---|
io.total_bytes_read |
uint64 |
bytes | The total amount of bytes read from storage |
io.total_bytes_written |
uint64 |
bytes | The total amount of bytes written to storage |
storage Metrics
Metrics on storage operations, such as attaching databases, writing to the WAL and checkpointing.
| Name | Type | Unit | Description |
|---|---|---|---|
storage.attach_load_storage_latency |
double |
seconds | Time spent loading from storage |
storage.attach_replay_wal_latency |
double |
seconds | Time spent replaying the WAL file |
storage.checkpoint_latency |
double |
seconds | Time spent running checkpoints |
storage.commit_local_storage_latency |
double |
seconds | Time spent committing the transaction-local storage |
storage.total_vacuum_time |
double |
seconds | Total time spent running vacuum tasks during checkpointing |
storage.waiting_to_attach_latency |
double |
seconds | Time spent waiting to ATTACH a file |
storage.wal_replay_entry_count |
uint64 |
rows | The total number of entries to replay in the WAL |
storage.write_to_wal_latency |
double |
seconds | Time spent writing to the WAL |
operator Metrics
Metrics collected for each individual operator in the query plan. These are reported in the operator tree of the profiling output.
| Name | Type | Unit | Description |
|---|---|---|---|
operator.cpu_time |
double |
seconds | CPU time spent in the operator |
operator.extra_info |
map |
Unique operator metrics | |
operator.intermediate_rows |
uint64 |
rows | Number of intermediate rows produced by the operator |
operator.intermediate_size_bytes |
uint64 |
bytes | Intermediate size in bytes produced by the operator |
operator.row_groups_scanned |
uint64 |
row_groups | Number of row groups scanned by the operator |
operator.rows_scanned |
uint64 |
rows | Number of rows scanned by the operator |
operator.timing |
double |
seconds | Time spent in the operator |
operator.total_row_groups_to_scan |
uint64 |
row_groups | Total number of row groups available for the operator to scan |
operator.type |
string |
Type of the operator |
optimizer Metrics
Metrics measuring the time spent in the optimizers.
| Name | Type | Unit | Description |
|---|---|---|---|
optimizer.total_time |
double |
seconds | Time spent in all optimizers combined |
Additionally, each optimizer has a corresponding metric that follows the template optimizer.optimizer_name and measures the time (in seconds) spent in that optimizer. These metrics are only collected when the specific optimizer is enabled. The available optimizers can be queried using the duckdb_optimizers() table function:
optimizer.expression_rewriter, optimizer.filter_pullup, optimizer.filter_pushdown, optimizer.empty_result_pullup, optimizer.cte_filter_pusher, optimizer.regex_range, optimizer.in_clause, optimizer.join_order, optimizer.deliminator, optimizer.unnest_rewriter, optimizer.unused_columns, optimizer.statistics_propagation, optimizer.common_subexpressions, optimizer.common_aggregate, optimizer.column_lifetime, optimizer.build_side_probe_side, optimizer.limit_pushdown, optimizer.top_n, optimizer.compressed_materialization, optimizer.duplicate_groups, optimizer.reorder_filter, optimizer.sampling_pushdown, optimizer.join_filter_pushdown, optimizer.extension, optimizer.materialized_cte, optimizer.aggregate_function_rewriter, optimizer.late_materialization, optimizer.cte_inlining, optimizer.row_group_pruner, optimizer.top_n_window_elimination, optimizer.common_subplan, optimizer.join_elimination, optimizer.window_self_join, optimizer.projection_pullup, optimizer.outer_join_simplification, optimizer.row_number_rewriter, optimizer.partitioned_execution, optimizer.partial_aggregate_pushdown.
parser Metrics
Metrics on parsing the SQL query.
| Name | Type | Unit | Description |
|---|---|---|---|
parser.total_time |
double |
seconds | Time spent parsing the SQL query |
planner Metrics
Metrics on generating the logical plan.
| Name | Type | Unit | Description |
|---|---|---|---|
planner.binding_time |
double |
seconds | Time spent binding the logical plan |
planner.total_time |
double |
seconds | Time spent generating the logical plan |
physical_planner Metrics
Metrics on generating the physical plan.
| Name | Type | Unit | Description |
|---|---|---|---|
physical_planner.column_binding |
double |
seconds | Time spent binding the columns in the logical plan to physical columns |
physical_planner.create_plan |
double |
seconds | Time spent creating the physical plan |
physical_planner.resolve_types |
double |
seconds | Time spent resolving the types in the logical plan to physical types |
physical_planner.total_time |
double |
seconds | Time spent generating the physical plan |
Examples
The following example enables profiling, sets the output to a file and only collects the total query time along with the operator metrics.
CREATE TABLE students (name VARCHAR, sid INTEGER);
CREATE TABLE exams (eid INTEGER, subject VARCHAR, sid INTEGER);
INSERT INTO students VALUES ('Mark', 1), ('Joe', 2), ('Matthew', 3);
INSERT INTO exams VALUES (10, 'Physics', 1), (20, 'Chemistry', 2), (30, 'Literature', 3);
SET enable_profiling = 'json';
SET profiling_output = '/path/to/file.json';
SET tracked_metrics = ['query.total_time', 'operator.*'];
SELECT name
FROM students
JOIN exams USING (sid)
WHERE name LIKE 'Ma%';
The file's content after executing the query:
{
"operator": [
{
"extra_info": {},
"intermediate_rows": 0,
"intermediate_size_bytes": 0,
"timing": 5.458e-06,
"type": "RESULT_COLLECTOR",
"children": [
{
"extra_info": {
"Projections": "name",
"Estimated Cardinality": "1"
},
"intermediate_rows": 2,
"intermediate_size_bytes": 40,
"timing": 8.3e-08,
"type": "PROJECTION",
"children": [
{
"extra_info": {
"Join Type": "INNER",
"Conditions": "sid = sid",
"Estimated Cardinality": "1"
},
"intermediate_rows": 2,
"intermediate_size_bytes": 48,
"timing": 4.4209e-05,
"type": "HASH_JOIN",
"children": [
...
"query": {
"total_time": 0.001491167
}
}
The second example collects all query and planner metrics, as well as the total time spent in the optimizers.
SET tracked_metrics = ['query.*', 'planner.*', 'optimizer.total_time'];
SELECT name
FROM students
JOIN exams USING (sid)
WHERE name LIKE 'Ma%';
The contents of the output file:
{
"optimizer": {
"total_time": 0.000179833
},
"planner": {
"binding_time": 5e-05,
"total_time": 6.8959e-05
},
"query": {
"cpu_time": 5.8541999999999996e-05,
"sql": "SELECT name FROM students JOIN exams USING (sid) WHERE name LIKE 'Ma%';\n",
"total_intermediate_rows": 8,
"total_intermediate_size_bytes": 136,
"total_row_groups_scanned": 2,
"total_row_groups_to_scan": 2,
"total_rows_scanned": 6,
"total_time": 0.001529
}
}