sql-mandelbrot-benchmark
Because why benchmark sql engines with boring aggregates when you can generate fractals?
This project uses recursive Common Table Expressions (CTE) to calculate the Mandelbrot set entirely in SQL ā no loops, no procedural code, just pure SQL. It serves as a fun and visually appealing benchmark for testing recursive query performance, floating-point precision, and computational capabilities of SQL engines.
What is This?
A benchmark suite that:
- Computes the famous Mandelbrot set using SQL recursive CTEs
- Tests multiple SQL engines, currently just DuckDB and a Python implementation for reference.
- Generates beautiful fractal images as proof of correct computation
- Reveals which database / SQL engine renders infinity fastest
Quick Start
# Clone the repository git clone https://github.com/yourusername/duckbrot.git cd duckbrot # Install dependencies pip install -r requirements.txt # Run the benchmark suite python main.py
Current Benchmark Results
Current results on 1400x800 pixels, 256 max iterations, Macbook Pro M4 Max:
| š | Engine/Implementation | Time (ms) | Relative Performance |
|---|---|---|---|
| * | Mac Metal GPU (unfair, but the true limit) | 0.77 ms | ā šµ |
| 1 | NumPy (vectorized, unrolled) | 665 ms | 0.83x ā |
| 2 | ArrowDatafusion (SQL) | 797 ms | 1.00x (baseline) |
| 3 | DuckDB (SQL) | 1,364 ms | 1.71x slower |
| 4 | FasterPybrot | 2,850 ms | 3.58x slower |
| 5 | FastPybrot | 3,327 ms | 4.17x slower |
| 6 | Pure Python | 4,328 ms | 5.43x slower |
| 7 | SQLite (SQL) | 44,918 ms | 56.36x slower |
Winner overall: NumPy - Just 17% faster than ArrowDatafusion using loop unrolling and vectorized operations!
Winner SQL: ArrowDatafusion - Incredibly fast, nearly matching optimized NumPy performance!
How It Works
The Mandelbrot set is computed by iterating the formula z = z² + c for each pixel in the complex plane:
WITH RECURSIVE -- Generate pixel grid and map to complex plane pixels AS ( SELECT x, y, -2.5 + (x * 3.5 / width) AS cx, -1.0 + (y * 2.0 / height) AS cy FROM generate_series(0, width-1) AS x, generate_series(0, height-1) AS y ), -- Recursively iterate z = z² + c mandelbrot_iterations AS ( SELECT x, y, cx, cy, 0.0 AS zx, 0.0 AS zy, 0 AS iteration FROM pixels UNION ALL SELECT x, y, cx, cy, zx * zx - zy * zy + cx AS zx, 2.0 * zx * zy + cy AS zy, iteration + 1 FROM mandelbrot_iterations WHERE iteration < max_iterations AND (zx * zx + zy * zy) <= 4.0 ) SELECT x, y, MAX(iteration) AS depth FROM mandelbrot_iterations GROUP BY x, y;
The iteration count determines the color of each pixel, creating the iconic fractal pattern.
Adding New Benchmarks
Want to test PostgreSQL, MySQL, MariaDB, SQLite or even Oracle or SQL-Server? Just:
- Create a new file (e.g.,
postgresqlbrot.py) - Implement a
run_postgresqlbrot(width, height, max_iterations)function (the DuckDB implementation is a good starting point) - Add one line to
main.py:BENCHMARKS = [ ("DuckDB (SQL)", "duckbrot", "run_duckbrot"), ("Pure Python", "pybrot", "run_pybrot"), ..., ("PostgreSQL", "postgresqlbrot", "run_postgresqlbrot"), # New! ]
The framework handles everything else automatically!
Configuration
Adjust the benchmark parameters in main.py:
WIDTH = 1400 # Image width in pixels HEIGHT = 800 # Image height in pixels MAX_ITERATIONS = 256 # Maximum recursion depth
Higher values = more detail, longer computation time.
Known Engine Compatibility
ā Works Great
- NumPy - Highly optimized with loop unrolling and vectorized operations (fastest!)
- DuckDB - Excellent performance, proper DOUBLE precision
- Pure Python - Reference implementation, just to have an idea how fast the database engines are
- SQLite - Works but significantly slower due to recursive CTE overhead
Should Work (untested, please contribute š¤)
- PostgreSQL (with proper recursive CTE support)
- SQLite (may need query adjustments)
- others
Known Issues
- Some engines might struggle with support for DOUBLE precision and may use DECIMAL (not good for fractals, and lead to pixelated results)
- Watch out for type inference - explicit
::DOUBLEcasts are critical!
What This Tests
This benchmark evaluates:
- Recursive CTE Performance - How efficiently engines handle deep recursion
- Floating-Point Precision - DOUBLE vs DECIMAL arithmetic accuracy
- Query Optimization - How well engines optimize complex recursive queries
- Scalability - Performance with increasing iterations and resolution
Contributing
Contributions very welcome! Especially:
- New SQL engine implementations (PostgreSQL, MySQL, SQLite, etc.)
- Performance optimizations
- Better visualization options
- Benchmark result submissions
License
MIT License - See LICENSE file for details.
Credits
Created by Thomas Zeutschler, Ulrich Ludmann, and Jakub Jirak (the grand master of GPU fractals)
Inspired by the mathematical beauty of the Mandelbrot set and the curiosity about SQL engine performance.
Learn More
Curious which database renders infinity fastest? Clone and find out! š
