-
-
Notifications
You must be signed in to change notification settings - Fork 26
Feat/performance benchmarks #134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
1fa6346
a820d13
4e0834c
786f1ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,8 +3,51 @@ | |||||||||||
| This directory contains comprehensive performance benchmarks for the `nexum_core` module using the [Criterion](https://github.com/bheisler/criterion.rs) benchmarking framework. | ||||||||||||
|
|
||||||||||||
| ## Benchmark Categories | ||||||||||||
| ## Performance & Benchmarks (Feb 2026) | ||||||||||||
|
Comment on lines
5
to
+6
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Orphaned heading: "Benchmark Categories" has no content before the next heading. Line 5 ( 🧹 Proposed fix-## Benchmark Categories
## Performance & Benchmarks (Feb 2026)
+
To maintain the high performance expected of a Rust-based engine, NexumDB is continuously benchmarked against SQLite using the `criterion` suite.📝 Committable suggestion
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.20.0)[warning] 5-5: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 6-6: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 6-6: Headings should be surrounded by blank lines (MD022, blanks-around-headings) 🤖 Prompt for AI Agents |
||||||||||||
| To maintain the high performance expected of a Rust-based engine, NexumDB is continuously benchmarked against SQLite using the `criterion` suite. | ||||||||||||
|
|
||||||||||||
| ### 1. Storage Engine Benchmarks (`storage_bench.rs`) | ||||||||||||
| ### Comparative Performance Results | ||||||||||||
| | Operation | SQLite | NexumDB | Delta | | ||||||||||||
| | :--- | :--- | :--- | :--- | | ||||||||||||
| | **Single INSERT** | 15.18 ms | **7.48 ms** | NexumDB ~2x Faster | | ||||||||||||
| | **Point SELECT (Cold)** | **140.5 µs** | 1.86 ms | SQLite Faster | | ||||||||||||
| | **Point SELECT (Cached)**| **143.8 µs** | 1.87 ms | SQLite Faster | | ||||||||||||
|
Comment on lines
+10
to
+14
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Benchmark results are based on flawed comparison benchmarks. The SELECT results in this table are invalid because the underlying benchmark ( 🧰 Tools🪛 markdownlint-cli2 (0.20.0)[warning] 10-10: Tables should be surrounded by blank lines (MD058, blanks-around-tables) 🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| ### Analysis | ||||||||||||
|  | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Broken image path — relative reference is wrong. This README lives at -
+📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| ### Architectural Insights | ||||||||||||
|
|
||||||||||||
| #### 1. Write Throughput: The LSM-Tree Advantage | ||||||||||||
| NexumDB’s storage engine (`sled`) utilizes a **Log-Structured Merge-tree (LSM-tree)**, whereas SQLite uses a traditional **B-tree**. | ||||||||||||
| * **LSM-tree (NexumDB):** Optimizes for writes by batching updates into immutable segments, leading to the 2x speedup observed in our `INSERT` benchmarks. | ||||||||||||
| * **B-tree (SQLite):** Optimized for reads. Every write requires finding a leaf node on disk, which involves more synchronous I/O. | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| #### 2. Read Latency & AI Overhead | ||||||||||||
| In small-scale point lookups (1,000 rows), SQLite's raw C-speed is superior. NexumDB's current ~1.8ms latency includes: | ||||||||||||
| * **SQL Parsing**: Converting strings to `Statement` enums. | ||||||||||||
| * **PyO3 Bridge**: The overhead of crossing the Rust-Python boundary for AI-native planning. | ||||||||||||
| * **Semantic Caching**: The current benchmark dataset is too small to show the "skip-the-disk" benefits of semantic caching, which scale exponentially with query complexity and data volume. | ||||||||||||
|
Comment on lines
+29
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Claims about PyO3 bridge overhead are unsupported by the benchmark. The benchmark executor is created without 🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| --- | ||||||||||||
|
|
||||||||||||
| ## Architecture | ||||||||||||
| * **Core System**: Rust-based storage engine using `sled`, with SQL parsing and intelligent execution. | ||||||||||||
| * **AI Engine**: Python-based semantic caching, NL translation, and RL optimization via local models. | ||||||||||||
| * **Integration**: PyO3 bindings for seamless Rust-Python interoperability. | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| ## Features | ||||||||||||
| ### v0.4.0 - Core Correctness & Table Management | ||||||||||||
| * **Projection-Correct SELECT**: Column/alias projection with schema validation. | ||||||||||||
| * **Schema-Safe Writes**: INSERT/UPDATE validation with best-effort coercion. | ||||||||||||
| * **Table Management**: SHOW TABLES, DESCRIBE, DROP TABLE (IF EXISTS). | ||||||||||||
| * **Performance Suite**: Integrated benchmark framework for regression testing. | ||||||||||||
|
Comment on lines
+6
to
+48
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix markdown formatting issues flagged by markdownlint. Multiple headings lack required surrounding blank lines, the table (lines 10-14) needs surrounding blank lines, and there's a trailing space on line 22. These are all flagged by markdownlint (MD022, MD058, MD009). As per coding guidelines, "Check documentation clarity, spelling, grammar, and formatting." 🧰 Tools🪛 markdownlint-cli2 (0.20.0)[warning] 6-6: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 6-6: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 9-9: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 10-10: Tables should be surrounded by blank lines (MD058, blanks-around-tables) [warning] 16-16: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 21-21: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 22-22: Trailing spaces (MD009, no-trailing-spaces) [warning] 28-28: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 36-36: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 43-43: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 44-44: Headings should be surrounded by blank lines (MD022, blanks-around-headings) [warning] 44-44: Headings should be surrounded by blank lines (MD022, blanks-around-headings) 🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| --- | ||||||||||||
|
|
||||||||||||
| Tests the performance of the underlying storage engine operations: | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| use criterion::{black_box, criterion_group, criterion_main, Criterion}; | ||
| use rusqlite::Connection; | ||
| use tempfile::{NamedTempFile, tempdir}; | ||
|
|
||
| use nexum_core::storage::StorageEngine; | ||
| use nexum_core::executor::Executor; | ||
| use nexum_core::sql::parser::Parser; | ||
|
|
||
| fn setup_sqlite() -> Connection { | ||
| let db_file = NamedTempFile::new().unwrap(); | ||
| let conn = Connection::open(db_file.path()).unwrap(); | ||
| conn.execute("CREATE TABLE bench (id INTEGER PRIMARY KEY, val TEXT)", []).unwrap(); | ||
| conn | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| fn setup_nexum() -> Executor { | ||
| let db_path = tempdir().unwrap(); | ||
| let storage = StorageEngine::new(db_path.path()).unwrap(); | ||
| let executor = Executor::new(storage); | ||
|
|
||
| let sql = "CREATE TABLE bench (id INTEGER, val TEXT)"; | ||
| // Removed .remove(0) because parse returns a Statement directly | ||
| let statement = Parser::parse(sql).unwrap(); | ||
| executor.execute(statement).unwrap(); | ||
|
|
||
| executor | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| fn bench_inserts(c: &mut Criterion) { | ||
| let mut group = c.benchmark_group("Insert_Performance"); | ||
|
|
||
| group.bench_function("SQLite_Single_Insert", |b| { | ||
| let conn = setup_sqlite(); | ||
| b.iter(|| { | ||
| conn.execute("INSERT INTO bench (val) VALUES ('test_data')", []).unwrap(); | ||
| }); | ||
| }); | ||
|
|
||
| group.bench_function("NexumDB_Single_Insert", |b| { | ||
| let executor = setup_nexum(); | ||
| let sql = "INSERT INTO bench (id, val) VALUES (1, 'test_data')"; | ||
| let statement = Parser::parse(sql).unwrap(); | ||
| b.iter(|| { | ||
| executor.execute(statement.clone()).unwrap(); | ||
| }); | ||
| }); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| group.finish(); | ||
| } | ||
|
|
||
| fn bench_selects(c: &mut Criterion) { | ||
| let mut group = c.benchmark_group("Select_Performance"); | ||
| let row_count = 1000; | ||
|
|
||
| let sqlite_conn = setup_sqlite(); | ||
| for i in 0..row_count { | ||
| sqlite_conn.execute("INSERT INTO bench (id, val) VALUES (?1, 'data')", [i]).unwrap(); | ||
| } | ||
|
|
||
| let nexum_executor = setup_nexum(); | ||
| let insert_sql = "INSERT INTO bench (id, val) VALUES (1, 'data')"; | ||
| let insert_stmt = Parser::parse(insert_sql).unwrap(); | ||
| for _ in 0..row_count { | ||
| nexum_executor.execute(insert_stmt.clone()).unwrap(); | ||
| } | ||
|
|
||
| let select_sql = "SELECT val FROM bench WHERE id = 500"; | ||
| let select_stmt = Parser::parse(select_sql).unwrap(); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| group.bench_function("SQLite_Point_Lookup", |b| { | ||
| b.iter(|| { | ||
| let mut stmt = sqlite_conn.prepare("SELECT val FROM bench WHERE id = 500").unwrap(); | ||
| let _ = stmt.query_row([], |r| r.get::<_, String>(0)).unwrap(); | ||
| }); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| }); | ||
|
|
||
| group.bench_function("NexumDB_Point_Lookup_Cold", |b| { | ||
| b.iter(|| { | ||
| black_box(nexum_executor.execute(select_stmt.clone()).unwrap()); | ||
| }); | ||
| }); | ||
|
|
||
| group.bench_function("NexumDB_Point_Lookup_Cached", |b| { | ||
| nexum_executor.execute(select_stmt.clone()).unwrap(); | ||
| b.iter(|| { | ||
| black_box(nexum_executor.execute(select_stmt.clone()).unwrap()); | ||
| }); | ||
| }); | ||
|
Comment on lines
+67
to
+83
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Cold" vs "Cached" distinction is meaningless — no semantic cache is enabled.
Either enable the cache via 🤖 Prompt for AI Agents |
||
|
|
||
| group.finish(); | ||
| } | ||
|
|
||
| criterion_group!(benches, bench_inserts, bench_selects); | ||
| criterion_main!(benches); | ||
|
Comment on lines
+88
to
+89
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's see the full content of the db_comparison.rs file to understand what benchmarks are defined
cat -n nexum_core/benches/db_comparison.rsRepository: aviralgarg05/NexumDB Length of output: 4260 🏁 Script executed: # Search for INSERT benchmarks in the codebase
rg -rn 'bench_insert\|Insert_Performance\|insert.*bench' --type rustRepository: aviralgarg05/NexumDB Length of output: 46 🏁 Script executed: # Search more broadly for all benchmark files
find nexum_core/benches -type f -name "*.rs"Repository: aviralgarg05/NexumDB Length of output: 239 🏁 Script executed: # Search for any bench_insert, bench_update, bench_delete functions anywhere
rg 'fn bench_insert|fn bench_update|fn bench_delete|fn bench_inserts|fn bench_updates|fn bench_deletes' --type rustRepository: aviralgarg05/NexumDB Length of output: 46 🏁 Script executed: # Check if there are any other benchmark-related files or functions
git ls-files nexum_core/benches/Repository: aviralgarg05/NexumDB Length of output: 341 🏁 Script executed: # Search in all benchmark files for INSERT, UPDATE, DELETE related benchmarks
rg -n 'INSERT|UPDATE|DELETE|insert|update|delete' nexum_core/benches/ --type rust -C 2Repository: aviralgarg05/NexumDB Length of output: 8381 🏁 Script executed: # Check the PR description or issue context - look for references to INSERT, UPDATE, DELETE
cat nexum_core/benches/README.mdRepository: aviralgarg05/NexumDB Length of output: 8867 🏁 Script executed: # Check all benchmark files to see what functions they define
for file in nexum_core/benches/*.rs; do
echo "=== $file ==="
grep -n 'fn bench_\|criterion_group!\|criterion_main!' "$file"
doneRepository: aviralgarg05/NexumDB Length of output: 602 🏁 Script executed: # Check if there's any reference to PR `#90` or issue context in git commits or files
rg -i 'issue.*90|PR.*90|INSERT.*benchmark|bench.*insert.*UPDATE.*DELETE' --type rust --type mdRepository: aviralgarg05/NexumDB Length of output: 1265 🏁 Script executed: # Look at executor_bench.rs more closely to see criterion_group registration
sed -n '289,298p' nexum_core/benches/executor_bench.rsRepository: aviralgarg05/NexumDB Length of output: 345 db_comparison.rs lacks comprehensive benchmark coverage. Only SELECT benchmarks are registered; INSERT, UPDATE, and DELETE benchmarks are missing. The To align with the documented benchmark results and complete the comparison, add 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,9 +1,12 @@ | ||||||||||||||||||||||||||||||||||||
| use std::time::Duration; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| use nexum_core::StorageEngine; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| fn storage_write_throughput(c: &mut Criterion) { | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
1
to
10
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Unnecessary blank lines added. Lines 3, 8, and 9 introduce extra blank lines that don't improve readability. Consider removing them to keep formatting consistent. 🧹 Remove superfluous blank lines use std::time::Duration;
-
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use nexum_core::StorageEngine;
-
-
fn storage_write_throughput(c: &mut Criterion) {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
| let mut group = c.benchmark_group("storage_write"); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,27 @@ | ||||||||||||||||||||||||
| import matplotlib.pyplot as plt | ||||||||||||||||||||||||
|
Comment on lines
+1
to
+6
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unused
♻️ Proposed fix import json
import argparse
-import sys
from pathlib import Path
from typing import Dict, List, Optional
import matplotlib.pyplot as plt📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||
| import numpy as np | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Data from our bench run | ||||||||||||||||||||||||
| labels = ['INSERT', 'SELECT (Cold)', 'SELECT (Cached)'] | ||||||||||||||||||||||||
| sqlite_times = [15.18, 0.143, 0.143] # converted to ms | ||||||||||||||||||||||||
| nexum_times = [7.48, 1.86, 1.87] # in ms | ||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| x = np.arange(len(labels)) | ||||||||||||||||||||||||
| width = 0.35 | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| fig, ax = plt.subplots(figsize=(10, 6)) | ||||||||||||||||||||||||
| rects1 = ax.bar(x - width/2, sqlite_times, width, label='SQLite', color='#3498db') | ||||||||||||||||||||||||
| rects2 = ax.bar(x + width/2, nexum_times, width, label='NexumDB', color='#e74c3c') | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| ax.set_ylabel('Latency (ms) - Lower is Better') | ||||||||||||||||||||||||
| ax.set_title('NexumDB vs SQLite Performance Comparison') | ||||||||||||||||||||||||
| ax.set_xticks(x) | ||||||||||||||||||||||||
| ax.set_xticklabels(labels) | ||||||||||||||||||||||||
| ax.legend() | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Log scale helps see the SELECT differences more clearly | ||||||||||||||||||||||||
| ax.set_yscale('log') | ||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| plt.tight_layout() | ||||||||||||||||||||||||
| plt.savefig('bench_results.png') | ||||||||||||||||||||||||
| print("Chart saved as bench_results.png") | ||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
rusqlite crate latest version crates.io💡 Result:
The latest
rusqliteversion on crates.io is0.38.0. [1][2]Cargo.toml:
Sources: [1][2]
🌐 Web query:
rusqlite 0.31.0 security advisory vulnerability💡 Result:
No specific security advisory appears to target rusqlite 0.31.0. The two main RustSec advisories for rusqlite list affected versions older than 0.31.0, meaning 0.31.0 is not in their vulnerable ranges:
For context, rusqlite 0.31.0 is a later release line than those fixed versions. [3]
Sources: [1] [2] [3]
🏁 Script executed:
Repository: aviralgarg05/NexumDB
Length of output: 206
Update
rusqliteto the latest version.rusqlite 0.31.0is free of known security advisories, but version0.38.0is the current latest release. Consider updating to benefit from bug fixes and improvements across 7 minor versions.🤖 Prompt for AI Agents