Better JIT for Postgres
83 points
6 hours ago
| 7 comments
| github.com
| HN
sourcegrift
2 hours ago
[-]
We have everything optimized, and yet somehow DB queries need to be "interpreted" at runtime. There's no reason for DB queries to not be precompiled.
reply
Asm2D
21 minutes ago
[-]
Many SQL engines have JIT compilers.

The problems related to PostgreSQL are pretty much all described here. It's very difficult to do low-latency queries if you cannot cache the compiled code and do it over and over again. And once your JIT is slow you need a logic to decide whether to interpret or compile.

I think it would be the best to start interpreting the query and start compilation in another thread, and once the compilation is finished and interpreter still running, stop the interpreter and run the JIT compiled code. This would give you the best latency, because there would be no waiting for JIT compiler.

reply
catlifeonmars
1 hour ago
[-]
This is a neat idea. I want to take it further and precompile the entire DBMS binary for a specific schema.
reply
WJW
21 minutes ago
[-]
How will you handle ALTER TABLE queries without downtime?
reply
catlifeonmars
8 minutes ago
[-]
[delayed]
reply
SigmundA
1 hour ago
[-]
Postgresql uses a process per connection model and it has no way to serialize a query plan to some form that can be shared between processes, so the time it takes to make the plan including JIT is very important.

Most other DB's cache query plans including jitted code so they are basically precompiled from one request to the next with the same statement.

reply
hans_castorp
1 hour ago
[-]
> and it has no way to serialize a query plan to some form that can be shared between processes

https://www.postgresql.org/docs/current/parallel-query.html

"PostgreSQL can devise query plans that can leverage multiple CPUs in order to answer queries faster."

reply
SigmundA
57 minutes ago
[-]
Nothing to do with plan caching, thats just talking about plan execution of parallel operations which is that thread or process based in PG?

If process based then they can send small parts of plan across processes.

reply
hans_castorp
51 minutes ago
[-]
Ah, didn't see the caching part.

Plans for prepared statements are cached though.

reply
zaphirplane
1 hour ago
[-]
What do you mean ? Cause the obvious thing is a shared cache and if there is one thing the writers of a db know it is locking
reply
SigmundA
55 minutes ago
[-]
Sharing executable code between processes it not as easy as sharing data. AFAIK unless somethings changed recently PG shares nothing about plans between process and can't even share a cached plan between session/connections.
reply
llm_nerd
29 minutes ago
[-]
Executable code is literally just data that you mark as executable. It did the JIT code, and the idea that it can't then share it between processes is incomprehensible.

I was actually confused by this submission as it puts so much of an emphasis on initial compilation time, when every DB (apparently except for pgsql) caches that result and shares it/reuses it until invalidation. Invalidation can occur for a wide variety of reasons (data composition changing, age, etc), but still the idea of redoing it on every query, where most DBs see the same queries endlessly, is insane.

reply
eru
4 hours ago
[-]
> However, standard LLVM-based JIT is notoriously slow at compilation. When it takes tens to hundreds of milliseconds, it may be suitable only for very heavy, OLAP-style queries, in some cases.

I don't know anything here, but this seems like a good case for ahead of time compilation? Or at least caching your JIT results? I can image much of the time, you are getting more or less the same query again and again?

reply
olau
4 hours ago
[-]
Yes.

Some years ago we ported some code from querying out the data and tallying in Python (how many are in each bucket) to using SQL to do that. It didn't speed up the execution. I was surprised by that, but I guess the Postgres interpreter is roughly the same speed as Python, which when you think about it perhaps isn't that surprising.

But Python is truly general purpose while the core query stuff in SQL is really specialized (we were not using stored procedures). So if Pypy can get 5x speedup, it seems to me that it should be possible to get the same kind of speed up in Postgres. I guess it needs funding and someone as smart as the Pypy people.

reply
bob1029
3 hours ago
[-]
At some level the application needs to participate in the performance conversation too.

https://www.postgresql.org/docs/current/sql-prepare.html

reply
SigmundA
1 hour ago
[-]
Unless you cache query plans like other RDBMS's then the client manually managing that goes away and its not limited to a single connection.

MS SQL still has prepared statements and they really haven't been used in 20 years since it gained the ability to cache plans based on statement text.

reply
the_biot
1 hour ago
[-]
What sort of things are people doing in their SQL queries that make them CPU bound? Admittedly I'm a meat-and-potatoes guy, but I like mine I/O bound.

Really amazed to see not one but several generic JIT frameworks though, no idea that was a thing.

reply
wreath
2 minutes ago
[-]
I think reading queries that are always served from cache are CPU bound because it also involves locking the buffers etc and there is no I/O involved.
reply
martinald
1 hour ago
[-]
Anything jsonb in my experience is quickly CPU bound...
reply
throwaway140126
1 hour ago
[-]
PostgreSQL is Turing complete, so I guess they do what ever they want?
reply
swaminarayan
2 hours ago
[-]
Have you tested this under high concurrency with lots of short OLTP queries? I’m curious whether the much faster compile time actually moves the point where JIT starts paying off, or if it’s still mostly useful for heavier queries.
reply
fabian2k
4 hours ago
[-]
The last time I looked into it my impression was that disabling the JIT in PostgreSQL was the better default choice. I had a massive slowdown in some queries, and that doesn't seem to be an entirely unusual experience. It does not seem worth it to me to add such a large variability to query performance by default. The JIT seemed like something that could be useful if you benchmark the effect on your actual queries, but not as a default for everyone.
reply
pjmlp
3 hours ago
[-]
That is quite strange, given that big boys RDMS (Oracle, SQL Server, DB2, Informix,...) all have JIT capabilities for several decades now.
reply
SigmundA
1 hour ago
[-]
The big boys all cache query plans so the amount it time it take to compile is not really a concern.
reply
larodi
2 hours ago
[-]
sadly, no windows version yet AFAICT
reply
asah
4 hours ago
[-]
awesome! I wonder if it's possible to point AI at this problem and synthesize a bespoke compiler (per-architecture?) for postgresql expressions?
reply
kvdveer
4 hours ago
[-]
Two things are holding back current LLM-style AI of being of value here:

* Latency. LLM responses are measured in order of 1000s of milliseconds, where this project targets 10s of milliseconds, that's off by almost two orders of magnitute.

* Determinism. LLMs are inherently non-deterministic. Even with temperature=0, slight variations of the input lead to major changes in output. You really don't want your DB to be non-deterministic, ever.

reply
qeternity
2 hours ago
[-]
> LLMs are inherently non-deterministic.

This isn't true, and certainly not inherently so.

Changes to input leading to changes in output does not violate determinism.

reply
magicalhippo
1 hour ago
[-]
> This isn't true

From what I understand, in practice it often is true[1]:

Matrix multiplication should be “independent” along every element in the batch — neither the other elements in the batch nor how large the batch is should affect the computation results of a specific element in the batch. However, as we can observe empirically, this isn’t true.

In other words, the primary reason nearly all LLM inference endpoints are nondeterministic is that the load (and thus batch-size) nondeterministically varies! This nondeterminism is not unique to GPUs — LLM inference endpoints served from CPUs or TPUs will also have this source of nondeterminism.

[1]: https://thinkingmachines.ai/blog/defeating-nondeterminism-in...

reply
yomismoaqui
1 hour ago
[-]
Quoting:

"But why aren’t LLM inference engines deterministic? One common hypothesis is that some combination of floating-point non-associativity and concurrent execution leads to nondeterminism based on which concurrent core finishes first."

From https://thinkingmachines.ai/blog/defeating-nondeterminism-in...

reply
simonask
4 hours ago
[-]
> 1000s of milliseconds

Better known as "seconds"...

reply
olau
4 hours ago
[-]
The suggestion was not to use an LLM to compile the expression, but to use an LLM to build the compiler.
reply