Paper notes - Efficiently Compiling Efficient Query Plans for Modern Hardware

(personal summary based on the paper)

A common approach to executing queries in database systems is the classical iterator model introduced in the Volcano paper. This model is simple and flexible, and operates by having each plan node implement a next() method that returns one tuple at a time when called repeatedly.

However, this model incurs performance overhead due to the large number of virtual function calls (next()), which often rely on function pointers or interface dispatching. These calls can become expensive when executed millions of times.

To address this, some systems reduce the overhead by passing batches of tuples instead of single tuples between operators, enabling vectorized execution and reducing call frequency.


The paper introduces a query compilation technique that translates SQL queries into efficient machine code using the LLVM compiler framework. Instead of pulling tuples via next() calls, the execution model pushes data from producers to consumers. This allows data to remain in CPU registers and minimizes the overhead of memory loads and function calls. LLVM’s intermediate representation supports an unbounded number of virtual registers, hiding the complexity of actual register allocation.

The core strategies of the compilation model are:

- Data locality: Process data in a way that it stays in CPU registers as
  long as possible.
- Push-based execution: Push data down the pipeline instead of pulling it,
  improving code locality and reducing branching.
- LLVM-based compilation: Compile the query plan into native machine code
  for optimal performance.

Compiling Expressions

SQL query compilation begins as in traditional systems: the query is parsed, converted into a logical plan, and optimized. The key difference is that, instead of generating a physical execution plan, the system compiles the query into an imperative program using LLVM IR.

Most of the database infrastructure—such as index structures—is still implemented in C++. The compiled LLVM code calls into these C++ routines, and vice versa, leading to mixed-mode execution where performance-critical logic is handled by generated code, while complex data structures remain in C++.

Large and complex queries can generate sizable machine code. To manage this, the system avoids generating everything in one monolithic function and instead breaks the compiled logic into modular, reusable fragments. The compilation process also attempts to minimize conditional branches, producing branch-predictable code, which, for example, improved hash lookup performance by over 20%.

Conclusion

The paper shows a technique to compile query plans into efficient machine code using LLVM. It's a very interesting approach that compiles the entire query plan, rather than just the expression evaluation like PostgreSQL does.

Comments

Popular posts from this blog

Hacking PostgreSQL - How SQL is compiled using LLVM?

Paper notes - Exploiting Cloud Object Storage for High-Performance Analytics

Using git worktree to work with different PostgreSQL patches