Paste or drop the output of EXPLAIN ANALYZE to see where your query spends its time. Big plans welcome: nothing is uploaded, so there is no size limit.
Prefix your query with EXPLAIN. JSON gives the most detail, but the default text format works too.
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT JSON)
SELECT ...;For long queries, write the plan straight to a file instead of copying it out of the terminal, then drop plan.json on this page:
# put the EXPLAIN statement above in explain.sql, then:
psql "$DATABASE_URL" -XqAt -f explain.sql -o plan.jsonOr from inside an interactive psql session:
\pset format unaligned
\pset tuples_only on
\o plan.json
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT ...;
\oSETTINGS needs Postgres 12+. VERBOSE adds output columns and makes the plan bigger, which is fine here.
SELECT c.country,
count(*) AS items,
sum(li.quantity * li.unit_price) AS revenue
FROM orders o
JOIN customers c ON c.id = o.customer_id
JOIN line_items li ON li.order_id = o.id
WHERE o.created_at >= now() - interval '30 days'
AND o.status = 'shipped'
GROUP BY c.country
ORDER BY revenue DESC
LIMIT 10;