A Hairy PostgreSQL Incident
ardentperf.com
ardentperf.com
WHERE a IN()
With
WHERE a = ANY()
No matter the number of options in the ANY operator, it'll hash to the same query id. Semantics between ANY and IN are very slightly different, but 95% of the case it'll get the job done and provide better stats (by having all queries analyzed together).
And it’ll be more reliable, because `any` will be happy to take an empty array while `IN` will be very cross if given an empty tuple.
> `in` will be very cross
I like this. People should anthropomorphize their operators more.
Unfortunately I still don't find myself understanding it very well... And I'm a professional backend engineer. I just spend all day writing Python; I keep the database hits of my code to the minimum that I can, and if something is broken, I figure out how to fix it, and I call it a day. I don't know very much about SQL. Where should I start?
Another thing that took my use of databases to the next level, was using PostGraphile (https://www.graphile.org/postgraphile/). It takes a PostgreSQL database and provides a GraphQL endpoint for it. Use that as your only backend. You can use PostgreSQL row-level security to do access control (who can see or modify what). You can use PL/pgSQL to write business logic for higher level calculations. You can use constraints and triggers to do data validation. Each of these areas has an initially steep learning curve, and wonky syntax, but once you get over them you can implement many backends extremely quickly with them. And using PostGraphile where you only have SQL available (well, you can also add javascript extensions, but try to limit those) will be a great forcing function that will require you to scour stackoverflow and the excellent PostgreSQL docs to learn many of the useful corners of SQL you'd never learn otherwise.
A lot of this high-level engineering stuff feels so opaque. You outlined a clear heuristic: find a motivation to learn the tool, add artificial limits if necessary for your learning goals, then scout relevant resources to help you get unstuck. It seems simple when written out, but I always find myself trying to overload on uncontextualized information first, then feel confused about why I still don't know how to "make a neural net" or what have you.
I remember that the most irritating brownout I got due to a query plan change was when a 50 millisecond query started to use a seq scan, but on a table under 10 million rows, so it wasn’t obviously hanging like in the article, but took like 2-3s. It was just enough to fly under radar for our monitoring, but to make some important process much slower.
with dummy_table_name as materialized
(select stuff from table ...)
the intent becomes explicit. (FWIW, while the nonstandard "materialized" keyword here doesn't have the grammatical form of hints in other DBs, I've still described it in my org as "the only hint Postgres supports" because the closest equivalent in, say, Oracle, is a hint -- the apparently undocumented /+ materialize /)On SQL Server, we see it building the bitmap in the graphical query plan basically right away. We can see it in Query Store, and we can see it in sp_whoisactive. The actual query plan being used in production is listed. Then, a couple minutes later, you've deployed a query hint and the bitmap is gone. This is not a hypothetical scenario I am imagining; I have done exactly this, for exactly this problem with the query plan trying to build a bitmap on a huge table. This is a minor blip for SQL Server users and not a disaster that turns into a blog post.
At what point does PostgreSQL change their minds about officially supporting query hints in the base system? This isn't the first time I've read basically this exact blog post and then written this exact comment on HN.
Recently fixed an issue for performance ( MS SQL ) by just using "With INDEX index-name".
Very small PR actually. I couldn't write an blog post about it actually.
I mean sure, most of the time the DB is clever. But sometimes the developer knows best, why not provide the tools?
select i.OrderNumber, i.OrderDate, o.OrderShipped
from ix_Orders_OrderDate i
join Orders o on o.OrderNumber = i.OrderNumber
where i.OrderDate > '2022-02-01'Plus point, it made my query easier to understand too!
There actually is a “pg_hint_plan” [2] Postgres module that adds some hints to Postgres optimizer (but it’s not part of Postgres core as I understand):
[1] https://wiki.postgresql.org/wiki/OptimizerHintsDiscussion
The tools on SQL server for query optimization are better then postgres, but that doesn't always mean problems like the OP don't still occur. I have had more than one SQL server query plan go to hell over time as the tables grew and the optimizer started to make odd decisions.
Edit: to make this a little clearer, I regard the SQL server query optimizer system as "lawful evil". It follows its own rules relentlessly.
Yep, agreed, hints should be temporary workarounds (or just experimentation aid when developing/testing SQL performance to validate some hypothesis). But many of these temporary workarounds end up being permanent temporary workarounds :-) That’s why Oracle now has hints and parameters to make the optimizer ignore all other hints in the SQL code :-)
I’m skeptical of this rule of thumb. I’m sure people misuse hints. But if someone thinks they “need” hints, my guess is they’ve tried changing the query and indexes.
[Thread: SELECT slows down on sixth execution](https://postgrespro.com/list/thread-id/2070689)
If I'm wrong on this, I would desperately like someone more informed on this to correct me because it seems to me that you can force postgres to stick to a query plan, thus obviating the need for query hints
- DDL modifications to the used objects
- updated planner statistics for the used objects
- modification to search path
I would expect a major Postgres version upgrade to hit these conditions, so the OP problem would still occur. Nevertheless, thanks for the pointer - I had mostly forgotten about this possibility.
At Amazon they do a portion of the onboarding training like this, describing how things went south, often for trivial reasons, what happened and how it was fixed. More of this on HN please!
Write up: https://github.com/josephmate/ui-optimizer-postgres/blob/REL...
[1] https://github.com/josephmate/ui-optimizer-postgres/tree/REL...
PS: Definitely don't use this in production because the DB blocks, waiting for someone to confirm the plan ;)
The solution was to confine the planner's ability to do bad things. CTEs (like the article) are one way. Another is to pull work up into the application layer (for instance, keep the IN filter in the query but overfetch and filter the < piece in the app... Not always feasible but has saved me in the past).
Edit: Can’t speak much for MSSQL and DB2, but there are lots of similar problems in the Oracle world too, sometimes due to an app design that works against the intended use of the DB/optimizer, sometimes due to a database optimizer bug and sometimes just due to the complexity of estimating the optimal plan based on limited statistical summaries of the “shape of your data” and expectation that the optimization won’t take longer than a few milliseconds.
And no, hints are not always the solution. Sometimes they even are the culprit.
If I had a wish for Postgres, I'd rather have something like SQL profiles (or similar) where you can register an alternative plan with an existing query, not hints. Very often a full deployment in order to change a single SQL isn't an option.
that said, I'd still much rather spend my days inside Postgres than inside oracle.