All Products
Search
Document Center

AnalyticDB:Slow query diagnostics

Last Updated:Mar 28, 2026

AnalyticDB for PostgreSQL records slow queries automatically. To diagnose performance issues, query two built-in views in the postgres database: qmonitor.instance_slow_queries for instance-level analysis, and qmonitor.host_slow_queries for per-node analysis.

Prerequisites

Before you begin, ensure that:

Usage notes

  • Slow query logs retain data for the last 7 days and do not record failed queries.

  • SQL statements longer than 1,024 bytes are truncated in the log.

  • All SQL statements that take 1 second or longer, plus all DDL statements, are recorded by default. The threshold is controlled by the slow_query_min_duration Grand Unified Configuration (GUC) parameter. To ensure system stability, we recommend that you do not modify the default setting of this parameter.

Enable or disable slow query diagnostics

Connect to the postgres database and run the following commands.

To check the current status:

SHOW adbpg_feature_enable_query_monitor;

To enable the feature for a specific database:

-- Replace <database_name> with the name of your business database.
ALTER DATABASE <database_name> SET adbpg_feature_enable_query_monitor TO ON;

To disable the feature, set the value to OFF.

Query slow query logs

All examples below run against qmonitor.instance_slow_queries (instance level) or qmonitor.host_slow_queries (node level). Connect to the postgres database before running them.

For a full description of all fields in both views, see View fields.

By time range

Query all slow statements executed in the past 30 minutes:

SELECT
    query_start       AS "Start time",
    query_end         AS "End time",
    query_duration_ms AS "Duration (ms)",
    query_id          AS "Query ID",
    query             AS "SQL statement"
FROM qmonitor.instance_slow_queries
WHERE query_start >= now() - interval '30 min';

Query all slow statements executed on a specific date (for example, February 26, 2024):

SELECT
    query_start       AS "Start time",
    query_end         AS "End time",
    query_duration_ms AS "Duration (ms)",
    query_id          AS "Query ID",
    query             AS "SQL statement"
FROM qmonitor.instance_slow_queries
WHERE query_start >= '2024-02-26 00:00:00'
  AND query_end   <= '2024-02-27 00:00:00';

By resource consumption (instance level)

query_duration_ms is the sum of four sub-fields:

Sub-fieldWhat it measures
optimizer_duration_msTime to generate the execution plan
lock_wait_time_msTime waiting for locks
queue_wait_time_msTime waiting for a resource queue
executor_duration_msTime to run the query on the execution engine

When a query is slow, check which sub-field dominates to identify the bottleneck. For example, a high queue_wait_time_ms indicates resource queue contention rather than an execution problem.

Top 20 by CPU time in the past 30 minutes:

SELECT
    (cpu_time_ms / 1000)::text || ' s' AS "CPU time",
    query_start                         AS "Start time",
    query_end                           AS "End time",
    query_duration_ms                   AS "Duration (ms)",
    query_id                            AS "Query ID",
    query                               AS "SQL statement"
FROM qmonitor.instance_slow_queries
WHERE query_start >= now() - interval '30 min'
ORDER BY cpu_time_ms DESC
LIMIT 20;

Top 20 by memory usage in the past 30 minutes:

SELECT
    pg_size_pretty(mem_bytes) AS "Memory consumed",
    query_start               AS "Start time",
    query_end                 AS "End time",
    query_duration_ms         AS "Duration (ms)",
    query_id                  AS "Query ID",
    query                     AS "SQL statement"
FROM qmonitor.instance_slow_queries
WHERE query_start >= now() - interval '30 min'
ORDER BY mem_bytes DESC
LIMIT 20;
mem_bytes records the cumulative peak memory usage across nodes. This value approximates actual memory usage and is not exact because memory fluctuates during query execution.

Top 10 by CPU time in a specific time window (for example, 00:00–12:00 on February 26, 2024):

SELECT
    (cpu_time_ms / 1000)::text || ' s' AS "CPU time",
    query_start                         AS "Start time",
    query_end                           AS "End time",
    query_duration_ms                   AS "Duration (ms)",
    query_id                            AS "Query ID",
    query                               AS "SQL statement"
FROM qmonitor.instance_slow_queries
WHERE query_start >= '2024-02-26 00:00:00'
  AND query_end   <= '2024-02-26 12:00:00'
ORDER BY cpu_time_ms DESC
LIMIT 10;

By resource consumption (node level)

Use qmonitor.host_slow_queries to diagnose slow queries on a specific node.

Top 20 by CPU time on a node in the past 30 minutes:

SELECT
    (host_cpu_time_ms / 1000)::text || ' s' AS "CPU time",
    query_start                              AS "Start time",
    query_end                                AS "End time",
    query_duration_ms                        AS "Duration (ms)",
    query_id                                 AS "Query ID",
    query                                    AS "SQL statement"
FROM qmonitor.host_slow_queries
WHERE hostname    = '<node_hostname>'
  AND query_start >= now() - interval '30 min'
ORDER BY host_cpu_time_ms DESC
LIMIT 20;

Top 20 by memory usage on a node in the past 30 minutes:

SELECT
    pg_size_pretty(host_mem_bytes) AS "Memory consumed",
    query_start                    AS "Start time",
    query_end                      AS "End time",
    query_duration_ms              AS "Duration (ms)",
    query_id                       AS "Query ID",
    query                          AS "SQL statement"
FROM qmonitor.host_slow_queries
WHERE hostname    = '<node_hostname>'
  AND query_start >= now() - interval '30 min'
ORDER BY host_mem_bytes DESC
LIMIT 20;

Replace <node_hostname> with the actual hostname of the node to diagnose.

By user

Count slow queries per user in the past 10 minutes to identify which accounts generate the most slow queries:

SELECT
    user_name AS "User",
    COUNT(1)  AS "Slow query count"
FROM qmonitor.instance_slow_queries
WHERE query_start >= now() - interval '10 min'
GROUP BY user_name
ORDER BY COUNT(1) DESC;

By query ID

Retrieve the full details of a specific slow query by its ID:

SELECT * FROM qmonitor.instance_slow_queries
WHERE query_id = '<query_id>';

Export slow query logs

Use SELECT statements to export data from qmonitor.instance_slow_queries or qmonitor.host_slow_queries to an internal table, an Object Storage Service (OSS) bucket, or a MaxCompute table. For export methods, see Data Lake Analysis.

In AnalyticDB for PostgreSQL, indexes are created for slow query logs and slow query logs are partitioned on query_start. For better performance, always include query_start in the WHERE clause to avoid full table scans.

For example, to export logs from 13:00 to 16:00 on February 26, 2024:

-- Add this condition to your SELECT statement.
WHERE query_start >= '2024-02-26 13:00:00'
  AND query_start <= '2024-02-26 16:00:00'

Configure thresholds

Only superusers can modify these configuration items.

slow_query_min_duration

Controls the minimum execution time for a query to be recorded as a slow query. The default is 1s. You can also modify this configuration item to collect slow queries that consume less than 1 second.

  • If execution time is greater than or equal to this value, the SQL statement, execution time, and related metrics are recorded.

  • Set to -1 to disable slow query collection entirely.

To change the threshold for a specific database (requires superuser):

-- Collect slow queries that take 5 seconds or longer.
ALTER DATABASE '<database_name>' SET slow_query_min_duration = '5s';

To change the threshold for the current session only (any user can run this):

SET slow_query_min_duration = '5s';

slow_query_plan_min_duration

Controls the minimum execution time for a slow query's execution plan to be collected. The default is 10s.

  • If execution time is greater than or equal to this value, the execution plan is collected alongside the query metrics.

  • For ad-hoc plan inspection, use EXPLAIN instead—you do not need to collect plans automatically.

  • Set to -1 to disable execution plan collection entirely.

To change the threshold for a specific database (requires superuser):

ALTER DATABASE '<database_name>' SET slow_query_plan_min_duration = '10s';

To change the threshold for the current session only:

SET slow_query_plan_min_duration = '10s';

View fields

qmonitor.instance_slow_queries (instance level)

FieldTypeDescription
query_idtextUnique ID of the query.
session_idintegerID of the query session.
db_namecharacter varying(128)Name of the database queried.
user_namecharacter varying(128)Name of the user who initiated the query.
application_namecharacter varying(128)Application that initiated the query.
client_hostnamecharacter varying(128)Hostname of the client.
client_addrcharacter varying(128)IP address of the client.
client_portcharacter varying(32)Port of the client.
rsg_namecharacter varying(128)Resource group associated with the table accessed by the query.
query_starttimestamptzStart time of the query.
query_endtimestamptzEnd time of the query.
query_duration_msbigintTotal query time in milliseconds. Equal to optimizer_duration_ms + lock_wait_time_ms + queue_wait_time_ms + executor_duration_ms.
optimizer_duration_msbigintTime to generate the execution plan, in milliseconds. Complex SQL statements take longer.
lock_wait_time_msbigintLock wait time, in milliseconds.
queue_wait_time_msbigintTime waiting for a resource queue, in milliseconds.
executor_duration_msbigintTime to run the query on the execution engine, in milliseconds.
querytextText of the SQL statement.
is_plpgsqlbooleanWhether the query is a PL/pgSQL stored procedure.
query_optimizercharacter varying(16)Optimizer used. Valid values: ORCA, Planner.
access_tablestextName of the table accessed by the query.
result_rowsbigintNumber of rows returned. For INSERT statements, the number of rows inserted.
num_segmentsintegerNumber of compute nodes where the query ran.
num_slicesintegerNumber of slices in the query execution plan.
cpu_time_msnumericTotal CPU time in milliseconds, including the coordinator node and all compute nodes.
mem_bytesnumericCumulative peak memory usage per node. Approximates actual memory usage; not an exact value.
spill_bytesnumericThe cumulative value of the maximum numbers of files that are saved to the disks on compute nodes where the query runs. This value roughly reflects the disk space consumed by the query but is not an exact value.

qmonitor.host_slow_queries (node level)

FieldTypeDescription
hostnamecharacter varying(128)Hostname of the node.
hostroletextRole of the node. Valid values: master (coordinator node), segment (compute node).
query_idtextUnique ID of the query.
db_namecharacter varying(128)Name of the database queried.
user_namecharacter varying(128)Name of the user who initiated the query.
query_starttimestamptzStart time of the query.
query_endtimestamptzEnd time of the query.
querytextText of the SQL statement.
query_duration_msbigintQuery execution time, in milliseconds.
optimizer_duration_msbigintTime to generate the execution plan, in milliseconds.
host_cpu_time_msnumericCPU time of the query on this node, in milliseconds.
host_mem_bytesnumericPeak memory usage of the query on this node.
host_spill_bytesnumericCumulative maximum data spilled to disk on this node.