Monitor Slow Queries with pgBadger
Learn to monitor slow queries with pgBadger in this PostgreSQL tutorial. Practical steps, troubleshooting, and next steps included.
Focus: monitor slow queries with pgbadger
Your database is responding in seconds, not milliseconds. Users are complaining, dashboards are red, and you have no idea which query is the culprit. You could enable log_min_duration_statement and manually sift through thousands of log lines — but that’s like finding a needle in a haystack while blindfolded. This lesson teaches you how to monitor slow queries with pgBadger, the tool that turns your PostgreSQL logs into a clear, actionable performance report. By the end, you'll not only identify the slow queries but also understand their patterns and be ready to fix them.
The problem this lesson solves
PostgreSQL is fast — until it isn't. Slow queries are inevitable as your data grows, indexes become less effective, or queries get more complex. The challenge isn't just having slow queries; it's finding them efficiently.
Without a monitoring strategy, you face a few painful realities:
- Manual log reading is tedious —
grepfordurationin a multi-GB log file is slow and error-prone. - You miss patterns — a query might be slow only at certain times or with specific parameters, and a single log line won't show you that.
- You can't prioritize — when everything is slow, which query do you fix first? You need data, not guesses.
pgBadger solves this by parsing PostgreSQL log files and generating an HTML report filled with charts, tables, and stats. It aggregates data, highlights the worst offenders, and gives you a bird’s-eye view of your database's performance. Instead of hunting for needle-in-a-haystack log lines, you get a structured report that tells you exactly where to look.
Pro tip: pgBadger is a log analyzer, not a real-time monitor. It works after the logs are written, which is perfect for periodic analysis, but if you need live dashboards, pair it with tools like pg_stat_statements or a monitoring agent (covered later).
Core concept / mental model
Think of pgBadger as your database performance auditor. You give it a log file, and it produces a comprehensive report, much like an auditor reviews financial records and produces a summary of the company's health.
The mental model has three stages:
- PostgreSQL writes logs — you configure PostgreSQL to log slow queries (using
log_min_duration_statement). - pgBadger reads the logs — it parses the log file, extracting timestamps, durations, query details, and more.
- You analyze the report — pgBadger generates an HTML file with tables, charts, and summaries that highlight the slowest queries, their frequency, and their impact.
Key terms you'll encounter:
- Log line format — the structure PostgreSQL uses to write log entries. pgBadger supports many formats (stderr, csvlog, syslog, jsonlog). You must set a compatible format.
- Log_min_duration_statement — the PostgreSQL setting that tells it to log any query that runs longer than X milliseconds. This is your primary data source.
- Report — the HTML output of pgBadger, containing sections like "Top Queries by Duration," "Hourly Distribution," and "Slowest Queries."
Analogy: A log file is like a raw data feed, and pgBadger is the analyst that turns that feed into a readable executive summary with charts and highlights.
How it works step by step
To monitor slow queries with pgBadger, you follow a sequence: configure PostgreSQL, run your workload (or let it run naturally), then run pgBadger on the resulting log file. Here's the logical flow:
- Enable slow query logging in PostgreSQL by setting
log_min_duration_statementto a threshold like1000(milliseconds). - Ensure the log format is compatible — the default
stderrformat works, butcsvlogis better because it includes structured fields. - Let your application run — queries that exceed the threshold will be written to the log file.
- Install pgBadger on your machine (it's a Perl script; no compilation needed).
- Run pgBadger on the log file, specifying the input and output files.
- Open the generated HTML report in your browser and analyze the results.
This step-by-step flow is repeatable — you can run pgBadger daily, weekly, or on-demand whenever you suspect a performance issue.
Hands-on walkthrough
Let's put this into practice. We'll configure PostgreSQL to log slow queries, generate some traffic, and then produce a pgBadger report.
Step 1: Configure PostgreSQL logging
Edit your postgresql.conf file (usually in /etc/postgresql/15/main/ or the data directory) and set these parameters:
log_min_duration_statement = 1000 # log queries taking >= 1 second
log_destination = 'stderr' # or 'csvlog' for structured output
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d.log'
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
Then restart PostgreSQL:
sudo systemctl restart postgresql
Now any query taking over 1 second will be logged.
Step 2: Generate slow queries
Let's create a table and run a slow query to generate log entries.
CREATE TABLE IF NOT EXISTS demo_numbers (id serial PRIMARY KEY, value numeric);
INSERT INTO demo_numbers (value) SELECT random() * 1000 FROM generate_series(1, 1000000);
-- Trigger a slow query (sequential scan on large table)
SELECT count(*) FROM demo_numbers WHERE value > 500;
If the query is fast (unlikely with 1M rows), lower the threshold or use a cross join.
Step 3: Install pgBadger
On Debian/Ubuntu, you can install from source or use the package manager. Here's the source method:
cd /tmp
wget https://github.com/darold/pgbadger/archive/v12.4.tar.gz
tar xzf v12.4.tar.gz
cd pgbadger-12.4
sudo perl Makefile.PL
sudo make install
Alternatively, use a package manager (e.g., apt install pgbadger on Debian).
Step 4: Run pgBadger
After your log file has accumulated entries, run pgBadger on it:
pgbadger /var/log/postgresql/postgresql-$(date +%Y-%m-%d).log -f stderr -o /tmp/report.html
If you used csvlog, change -f to csv.
Step 5: View the report
Open /tmp/report.html in your browser. You'll see sections like:
- Overall statistics — total queries, average duration.
- Top queries by total time — the queries that consumed the most time overall.
- Slowest queries — sorted by max duration.
- Hourly distribution — when slow queries occurred.
In the top queries table, you'll see the slow query we generated (count(*)), with its average and max duration, plus the query fingerprint. This fingerprint masks literals, so you can group similar queries even if parameter values differ.
Pro tip: Use the
-qflag to exclude normal queries if you're only interested in the slow ones. For example:pgbadger -q --exclude-query='^(SELECT|INSERT|UPDATE|DELETE) FROM pg_' -o /tmp/report.html yourlog.log.
Compare options / when to choose what
pgBadger isn't the only way to monitor slow queries. Here's how it stacks up against common alternatives:
| Tool/Action | What it does | Strengths | Weaknesses | Best for |
|---|---|---|---|---|
| pgBadger | Parses log files and generates an HTML report | Detailed, free, no DB extension needed, shows trends | Not real-time; requires log file access | Periodic analysis, root-cause investigation |
| pg_stat_statements | Tracks query execution statistics in a DB table | Real-time, maintains cumulative stats, easy to query | Requires extension, only shows aggregated stats, no exact query text | Continuous monitoring, identifying top offenders over time |
| EXPLAIN ANALYZE | Shows execution plan and actual timing for a single query | Deep insight into a specific query's execution | Only for one query; no historical data | Tuning a particular query after identifying it |
| Monitoring agents (e.g., pganalyze, Datadog) | Collects metrics and sends alerts | Real-time, automated, cloud-based | Costly, requires external service | Production environments with dedicated DBA teams |
When to choose pgBadger:
- You need a free, self-contained solution and already have log files.
- You want a visual report to share with your team.
- You're doing post-incident analysis and need to understand historical patterns.
Choose pg_stat_statements if you want a continuous, database-embedded view and don't mind writing SQL queries to inspect the data. For a quick one-off check of a single slow query, EXPLAIN ANALYZE is essential.
Pro tip: You can combine both — use pgBadger to get an overview and then use
EXPLAIN ANALYZEon the top queries to drill down into the execution plan.
Troubleshooting & edge cases
pgBadger reports "no log entries found"
This means your log file doesn't contain any lines that pgBadger can parse. Common causes:
- Wrong log format — ensure
log_destinationmatches the-fflag. If you setstderr, use-f stderr. If you setcsvlog, use-f csv. - No slow queries logged — your threshold (
log_min_duration_statement) might be too high, or your queries are all fast. Temporarily set it to0to log everything for testing. - Incorrect log file path — double-check the
log_directoryandlog_filenamesettings.
The report shows wrong durations or missing queries
- Log line prefix — pgBadger relies on the
log_line_prefixto extract timestamps and duration. Use a standard format like'%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '. If you omit parts, pgBadger may misparse. - Log rotation — if you're using log rotation (e.g.,
log_rotation_age), ensure you run pgBadger on the correct file. You might need to concatenate multiple files:cat postgresql-*.log | pgbadger -.
pgBadger crashes or stops parsing
- File size — very large logs can be slow. Use
--incrementalor split the log into smaller chunks. - Unsupported log format — some custom log formats confuse pgBadger. Stick to the standard
stderrorcsvlog.
The report is huge and hard to read
- Use filters:
--exclude-queryto ignore certain queries (e.g.,SELECT 1), or--include-queryto focus on specific patterns. - Limit the number of queries shown with
--top(e.g.,--top 10).
What you learned & what's next
You now know how to monitor slow queries with pgBadger — from configuring PostgreSQL logging to generating and interpreting an HTML report. You understand the core concept of log analysis, the step-by-step workflow, and how to choose pgBadger over alternatives. You also know common pitfalls and how to fix them.
With this skill, you can confidently identify which queries are hurting your database's performance and prioritize your optimization efforts.
In the next lesson, you'll learn how to analyze and optimize the slow queries you discovered using EXPLAIN and index tuning. You'll take the report from pgBadger and turn it into a list of concrete actions to speed up your database.
Keep practicing — the more you analyze logs, the quicker you'll spot performance patterns and prevent future slowdowns.
Practice recap
Try this: set log_min_duration_statement = 100, create a table with 100k rows, and run a few slow queries. Then run pgBadger on the log file and open the HTML report. Look at the 'Top queries by total time' section and see if you can spot the query you intentionally slowed down. Repeat this with the --top flag to limit the report to the worst offenders.
Common mistakes
- Forgetting to set
log_min_duration_statement— without it, PostgreSQL logs nothing and pgBadger reports no entries. - Mismatching
log_destinationand the-fflag — if you setstderrin PostgreSQL but pass-f csv, pgBadger can't parse the log. - Ignoring
log_line_prefix— if you use a custom prefix, pgBadger might misread timestamps or durations. - Running pgBadger on a log file that contains only fast queries because you set the threshold too high.
- Trying to use pgBadger for real-time monitoring — it analyzes historical logs, not live data.
Variations
- Use
pg_stat_statementsinstead of pgBadger to get a live, database-embedded view of query performance with cumulative stats. - Configure PostgreSQL to log to
csvloginstead ofstderr— pgBadger can parse it more reliably and with structured fields. - Use a monitoring service like Datadog or pganalyze to get automated alerts and dashboards, but they require external subscriptions.
Real-world use cases
- A DBA runs pgBadger weekly on production logs to identify the top 10 queries consuming the most time and plan index creation.
- A developer investigates a reported slowdown in a web app and uses pgBadger to confirm that a specific
JOINquery is the bottleneck. - A managed PostgreSQL platform automatically archives log files; a support engineer runs pgBadger on a customer's log to diagnose a performance complaint.
Key takeaways
- pgBadger converts raw PostgreSQL logs into an HTML report with charts and tables, making slow query analysis much easier.
- You must enable
log_min_duration_statementto capture slow queries — without it, pgBadger has no data to work with. - The
log_line_prefixandlog_destinationsettings must align with pgBadger's parsing options (-fflag). - pgBadger aggregates query fingerprints, helping you see patterns like frequency and average duration, not just individual occurrences.
- For real-time monitoring, combine pgBadger with
pg_stat_statementsor a dedicated monitoring agent. - After identifying slow queries with pgBadger, the logical next step is to use
EXPLAIN ANALYZEto understand and fix their execution plans.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.