Tips for a Healthier Postgres Database
blog.crunchydata.com
blog.crunchydata.com
We have a main database that started at version 9.6 and was upgraded along the way. The largest table is huge (billions of rows, TB’s of diskspace) and gets a lot of deletes and updates.
Vacuums could no longer finish on that table (we killed it after ~90 days).
Reindex (+ vacuum with skip-indexes) dropped our db load from 60 to 20 and fixed the autovacuums, which now take less than a day. The indexes on that table had accumulated a lot of bloat, and I think newer versions also improved the index disk layout.
We now have a monthly cron job to reindex all indexes.
However, we’re actually in the process of sharding the db, and by copying customer by customer we’ll lose the bloat that way. The subsequent shards will be a lot more manageable so we can run pg_repack there with more confidence.
I think I would recommend setting log_min_duration_statement first and watching the logs for some time before doing that. So that you know what's going to get whacked, have some opportunity to tune it, etc.
Edit: It is mentioned, so perhaps just talking about that prior to talking about setting the timeout.
The only time I've seen a running query lasting for days in prod was when a human database toucher had forgot their DBeaver tabs open after running a complex query with too few filters.
And every 6 months we noticed certain queries getting slower and slower. That's because the amount of data growth means we have to have a different approach to indexing or the way how we access it. So our queries change a few times a year.
Otherwise, on a 650 Gigabyte database, there is remarkably little maintenance needed, except testing restores on daily backups and testing replicas.
You don't need support to work with Postgresql. Everything is simple and works as documented.
After having worked with PostgreSQL, MySQL and Oracle I cannot understand why anyone would pick Oracle. Its advantages can't be worth the hassle even if we ignore the license fee.
We get much higher traffic during the daytime, so we now have a cronjob that runs VACUUM ANALYZE each night.
We also have some small metadata tables that are very update heavy as we sync these from another data store, replacing all rows each time. We now run VACUUM FULL on these after each sync (this locks the table but is fast (20-40ms) on such small tables) to avoid bloating them over time.
Doesn't autovacuum typically handle this automatically?
[1]: https://www.postgresql.org/message-id/flat/CA%2BTgmoZgapzekb... [2]: https://www.postgresql.org/message-id/flat/CAH2-Wz%3DsSvMX5H...
If this is such a standard requirement and the statistics are so vital to performance, why isn't something built-in to the engine to keep these up-to-date without a user intervention?
I don't have to run "ANALYZE" on DynamoDB daily to ensure performance doesn't tank.
One issue is that there is some counter-intuitive behaviour here, if you see the Autovacuum taking significant resources, the worst thing you can do is to let it run less often. You actually need to make it more aggressive in that kind of situation, and/or fix your usage pattern or add more resources.
If a manual ANALYZE is necessary, this can often indicate a misconfiguration of Postgres, e.g. someone reducing the Autovacuum frequency or disabling it entirely. Postgres also got a lot better at this, so it also matters how old your Postgres version is.
Why isn't that so?
Running these manual commands is just shifting the config tuning for large databases to periodic „manual“ operations.
Exploring pgbouncer when you have lots of idle connections is a great tip, but 20 idle connections feels _extremely_ low to me. I've seen postgres databases on AWS Aurora serving over 13,000 transactions per second with hundreds of idle connections (because of client side pooling with a few dozen backend clients) just fine. In fact, around that scale is when we switched _from_ pgbouncer to client side pooling to simplify our architecture, and we noticed no degradation in any major metrics.
[0] https://aws.amazon.com/blogs/database/set-up-highly-availabl...
https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide...
AWS has "only" replaced the storage layer.
For MySQL any of the big users like facebook & co. Are running (heavy) forked mysql versions with changes they need.
Does this mean PGbouncer is unnecessary for postgres > v14?
https://pganalyze.com/blog/postgres-14-performance-monitorin...
https://blog.crunchydata.com/blog/optimize-postgresql-server...
Ran into a pathological case where a query that usually took 10-20ms would sometimes, semi-randomly, take > 15 minutes (while the corresponding PG process server-side is running at 100% CPU)
Explain showed a dramatic query plan change, which led us towards bad table statistics.
There seems to be a common lifecycle of indexes within applications. First you start off with almost none, maybe a few on primary keys
Not to be rude or anything but I hope he doesn't mean this.Every single postgres primary key (and unique constraint) automatically gets an index. That's how the unique constraint is implemented. Primary keys being naturally unique.
'maybe' changes that dramatically unfortunately.
Very unfortunate if what you say is true. I guess I'll give him the benefit of the doubt then and go read the rest.
My skimming of the first few paragraphs was trying to do just that and my conclusion seems to have been the opposite of everyone else :)
Use this to get the values you need https://pgtune.leopard.in.ua/#/ .
This saved me a lot of headaches, and it just gets the server into a good enough state from which you can observe and optimise later.
I'd also add in monitoring early, add a Prometheus exporter https://github.com/prometheus-community/postgres_exporter and alerts https://awesome-prometheus-alerts.grep.to/rules#postgresql . There are a few Grafana dashboards available for the prometheus exporter, start with those.
We learned this the hard way. We altered some integer columns to bigint. That cleared the statistics for those column and caused terrible query plans. An ANALYZE fixes this, but it took us a few days to notice.
Since then we typically include an analyze statement whenever we do a large change, or rewrite a lot of rows.
Anyone care to comment on how PostgreSQL works out of the box without being an expert?
(I've run MySQL/MariaDB for almost 20 years and there are very few issues I've been surprised by)
I'd say the biggest footgun is really not knowing about the process per connection limitation, which is why the article mentions pg bouncer. Everything else in the article is pretty geared towards setting your db up for monitoring so you can head off issues.
Optimizations as presented by many are not needed right up front and you'll learn them as you go along. Good luck!
Has MySQL gotten... a lot better, or are you just used to its quirks? I feel like the UTF encoding and ... date format? timezones? are/were all really big footguns.
Date format... not sure, I just use datetime now, timezones I manage in app (never trusted db engine for that...) Maybe I avoided those by accident with unix time until I moved to datetime.
I know I can do research, get training, etc... but I have never done maintenance like this with MySQL/MariaDB, so it's the unknown unknowns that worry me.
Despite this calamitous oversight (wink), articles such as this are a great source to be able to draw on others' experience and reap the benefits of others hindsight without experiencing the outages or time consuming problems yourself.
Additionally, the linked article about checking for unused indexes is really helpful IMO.
https://blog.crunchydata.com/blog/cleaning-up-your-postgres-...
Obviously I love learning new things, but I've just never felt inclined to try it out, whereas I'm always jumping between other languages and frameworks within them. Not sure why that is.
You don’t realize how limited you are until you really get into all the additional capabilities that PG brings…and then have them unavailable.
MySQL clustering and operations tooling seems much better. No vacuums to worry about
> MySQL is a pretty poor database, and you should strongly consider using Postgres instead.
https://web.archive.org/web/20220104181634/https://blog.sess...
I would not choose MySQL over Postgresql because of this, never mind all the other features.
I find it pretty interesting that for the DB write-intensive portion[0] of the TechEmpower web framework benchmarks, you must go further than entry 150 (sorted by most requests-per-second) to find MySQL used, compared to PostgreSQL or Mongo. For the DB read-intensive portion[1], only 15 of the top 100 use MySQL (the rest in that bracket use PostgreSQL), and the first entry there comes in at number 44. Important: if you examine the entries, you'll find that some of the frameworks have multiple listings for different configurations, including the use of MySQL vs PostgreSQL (in other words: same framework, but only the DB is different, in the same test).
[0] https://www.techempower.com/benchmarks/#section=data-r20&hw=...
[1] https://www.techempower.com/benchmarks/#section=data-r20&hw=...
I’d highly recommend to try PostgreSQL yourself and learn it’s config, permissions, replication, administration and querying capabilities. You’ll appreciate PostgreSQL’s casting with :: for example. If you had to start from scratch, you’ll be better informed about PostgreSQL and can include it in your selection process.
When we used MySQL, we loved the ease of replication and tooling such as Monyog/Webyog/Workbench. When we used PostgreSQL, we loved the query optimizer and JSON functions.
My primary database these days is MongoDB, so I am a bit distanced from RDBMs now.