skip to content

How do you prove that slow Amazon Redshift dashboards are queueing rather than executing slowly?

level: seniorimportance: must knowfreq 65%

answer

  1. elapsed time has exactly two parts
  2. one of them WLM cannot fix
  3. measure before you add a queue
  4. per-query totals live in a WLM history view
  5. total_queue_time versus total_exec_time

basics

~20 s

Split each query's elapsed time into wait and run. In Redshift, STL_WLM_QUERY gives total_queue_time and total_exec_time per query, and SYS_QUERY_HISTORY exposes queue and execution time directly. High wait means a WLM problem; high run time means a query or table problem.

solid answer

~40 s

Every slow-query complaint on Redshift resolves into one number: how much of the elapsed time was **waiting**. `STL_WLM_QUERY` records `total_queue_time` and `total_exec_time` per query in microseconds, along with the `service_class` (the queue) and `slot_count`; on current clusters `SYS_QUERY_HISTORY` gives the same split without STL archaeology. Aggregate both by queue over the slow window and compare. For live triage, `STV_WLM_QUERY_STATE` shows what is running versus queued right now and `STV_WLM_SERVICE_CLASS_STATE` shows the per-queue backlog; CloudWatch's `WLMQueueLength` and `WLMQueueWaitTime` give the same picture as a time series you can align with the morning peak. If wait dominates, the remedies are WLM ones — routing, priority, concurrency scaling. If execution dominates, WLM is innocent and you go to the plan: distribution and sort keys, stale statistics, disk spill.

code

sql · 9 lines
sql
SELECT service_class,
       count(*)                          AS queries,
       avg(total_queue_time) / 1000000.0 AS avg_queue_s,
       avg(total_exec_time)  / 1000000.0 AS avg_exec_s,
       max(total_queue_time) / 1000000.0 AS max_queue_s
FROM   stl_wlm_query
WHERE  queue_start_time > dateadd(hour, -4, getdate())
GROUP  BY service_class
ORDER  BY avg_queue_s DESC;

go deeper

for a junior

Know that a slow Redshift query may have spent its time waiting rather than running, and that the system views record those two durations separately.

for a middle

Be able to name the views and write the aggregation: total_queue_time versus total_exec_time from STL_WLM_QUERY, or the equivalent columns in SYS_QUERY_HISTORY, grouped by queue.

for a senior

Demonstrate the full triage loop under pressure — measure the split, check which queue the traffic actually landed in, act on the dominant side, then re-measure to confirm rather than shipping a configuration change on a hunch.

for a principal

Own the observability itself: standing dashboards on queue wait per workload, alert thresholds tied to the business SLA, and retained snapshots so an incident three days old is still investigable.

## Split elapsed time before you do anything else "The dashboard is slow at 9am" is not yet a diagnosis. A query's elapsed time on Amazon Redshift is `queue time + execution time`, and the two have completely disjoint remedies. Adding queues, priorities or concurrency scaling does nothing for a query that is executing slowly; rebuilding sort keys does nothing for a query that spent four minutes waiting in line. So the first measurement is always the split. ## The views that give you the split **Historical, per query.** `STL_WLM_QUERY` has one row per query that passed through WLM, with `total_queue_time` and `total_exec_time` in microseconds, `service_class` identifying the queue, `slot_count`, and timestamps including `queue_start_time`. Aggregating it by queue over the complaint window is the standard first query: ```sql SELECT service_class, count(*) AS queries, avg(total_queue_time) / 1000000.0 AS avg_queue_s, avg(total_exec_time) / 1000000.0 AS avg_exec_s, max(total_queue_time) / 1000000.0 AS max_queue_s FROM stl_wlm_query WHERE queue_start_time > dateadd(hour, -4, getdate()) GROUP BY service_class ORDER BY avg_queue_s DESC; ``` On current clusters, `SYS_QUERY_HISTORY` exposes queue time and execution time per query directly and is the view AWS now points at; it also spans queries that ran on concurrency scaling clusters, which the older STL tables on the main cluster do not fully cover. **Live.** `STV_WLM_QUERY_STATE` shows every query WLM currently knows about and whether it is running or queued, with how long it has been waiting. `STV_WLM_SERVICE_CLASS_STATE` shows per-queue counts of running and queued queries, and `STV_WLM_SERVICE_CLASS_CONFIG` shows the configuration those numbers are being measured against — useful for catching the case where the parameter group you edited was never applied. **Time series.** CloudWatch publishes `WLMQueueLength`, `WLMQueueWaitTime`, `WLMRunningQueries` and `WLMQueryDuration` per queue. These are what you overlay with the business hours to prove the backlog is a 9am phenomenon rather than a constant. ## Reading the result **Wait dominates.** The queue is admitting fewer queries than are arriving. Check first whether the traffic is even landing in the queue you think it is — a common finding is that BI users match no queue at all and are piling into the default queue behind ETL. Then the remedies in order: route the workload to its own queue, give it a higher priority under automatic WLM, enable concurrency scaling on that queue so bursts spill onto transient clusters, and enable short query acceleration so quick queries are not stuck behind long reports. If the cluster is simply undersized for the concurrency, no WLM configuration fixes that. **Execution dominates.** WLM is not your problem. Go to the query: check `SVL_QUERY_SUMMARY` for steps with `is_diskbased = 't'` (memory spill), `STL_ALERT_EVENT_LOG` for planner alerts such as missing statistics or very selective filters, the distribution style for a large redistribution or broadcast, and whether the sort key supports the filter. Run `ANALYZE` if statistics are stale. **Both are moderate but the count exploded.** Sometimes nothing is slow and the dashboard simply issues 400 queries per refresh. Count queries per user and per query group before tuning anything. ## Traps worth naming - **Times are in microseconds** in the STL views. Reporting `total_queue_time` as seconds off by six orders of magnitude is an easy way to misdiagnose. - **STL tables are retained for a limited period** and rotate; if the incident was days ago the rows may be gone. Persist a nightly snapshot if you need history. - **Queue time excludes client-side and connection time.** If the user's elapsed time is much larger than queue plus execution, look at the leader node's compile time for a first-run query, at result set transfer, or at the BI tool itself. - **Compile time on first execution** of a new query shape can be seconds and is not queue time. A dashboard deployed this morning may be paying compilation once per new statement. ## How to present it The answer an interviewer wants is a decision procedure, not a view name: measure the split, act on whichever side dominates, and confirm the fix by re-measuring the same split. Naming `STL_WLM_QUERY`, `SYS_QUERY_HISTORY` and `STV_WLM_QUERY_STATE` proves you have actually done it.

  • The split shows almost all execution time and almost no queue time. What do you look at next?
    The query itself. Check `SVL_QUERY_SUMMARY` for steps with `is_diskbased = 't'`, `STL_ALERT_EVENT_LOG` for planner alerts like missing statistics or a very selective filter on an unsorted column, and the plan for a large broadcast or redistribution caused by mismatched distribution keys. Run `ANALYZE` if statistics are stale. No WLM change helps here.
  • Users report ten seconds of elapsed time but the system views show under one second of queue plus execution. Where did the time go?
    Outside query execution. The usual candidates are leader-node compilation of a first-seen query shape, result set transfer for a wide or large result, connection establishment, and time spent in the BI tool itself. Compare the client's timing against `SYS_QUERY_HISTORY` timestamps to locate the gap rather than tuning the cluster.
  • Why might yesterday's incident have no rows to investigate?
    The STL system tables are log tables retained for a limited window and they rotate as new activity arrives on a busy cluster. If you need history beyond that, snapshot the relevant WLM and query views into permanent tables on a schedule, or rely on CloudWatch metrics, which retain longer than the in-cluster logs.

saying these in an interview costs you the question

  • Adding WLM queues before measuring queue time
  • Reading microsecond columns as if they were seconds
  • Assuming slow means executing slowly, never waiting
  • Ignoring that the traffic may be landing in the default queue
  • Blaming the cluster when the gap is client-side or compile time

context