ElyraSQL 0.9.3: A single-file, MySQL-compatible database that speaks fluent AI
ElyraSQL is a MySQL-compatible SQL server in Rust where the whole database is one ACID file. 0.9.3 adds HYBRID() search — full-text and vector similarity fused with Reciprocal Rank Fusion — and ai_embed() for generating embeddings right in SQL. The core of a RAG stack, in a single file.
Or: how we put the whole RAG stack into one file — and kept it honest.
There's a certain kind of tired that comes from wiring together a "modern" data stack. You want a database. You also want vector search, so you add pgvector. You want good full-text, so you bolt on Elasticsearch. Then a reranker to make the two agree. Then a queue, a cache, a cron. By the time you've got a working app, you're running six services and a small YAML novel just to answer "find me documents that are both about privacy law and semantically close to this question."
ElyraSQL started from a simple, slightly stubborn idea: what if that all lived in one file?
So what is ElyraSQL?
ElyraSQL is a robust, MySQL-compatible SQL server written in Rust. Three things make it a little different from the databases you already know:
It speaks the MySQL wire protocol. Connect with
mysql, DBeaver, Workbench, sqlx, PyMySQL, JDBC — any MySQL driver, in any language. No custom client, no special SDK.SELECT VERSION()even reports a familiar-looking8.0.0-ElyraSQL-0.9.3.The entire database is a single ACID file (
*.edb), built on an MVCC key-value core. Backup iscp. Deployment is one binary. Dev/prod parity is free. Think of SQLite's "one file, no server to babysit" ergonomics — but with a real wire protocol, a query planner, transactions, and replication.It's built for the AI era, not retrofitted for it. Vector columns, HNSW nearest-neighbour, full-text, and OLAP aggregation are all first-class parts of the same engine — not four bolted-on extensions that have to be kept in sync.
It targets the SMB / single-box sweet spot: the enormous number of applications that don't need a five-node cluster and a full-time DBA, but do need something fast, correct, and pleasant to operate.
How fast is it, honestly?
Let's be upfront, because the project is: these are ElyraSQL's own reproducible numbers, not a controlled head-to-head against MySQL or Postgres. Those systems are mature and heavily tuned; benchmarketing against them with a laptop and a favorable query would be dishonest. What we can show you is that the fast paths are genuinely fast — and you can re-run every number on your own hardware with bench/benchmark.py.
1,000,000 rows, single client, medians (inside a Docker container):
Workload Median Bulk insert 1M rows ~5.3 s (~190,000 rows/s) PK point lookup 0.2 ms Selective join (index nested-loop) 0.3 ms Vector ANN, cached (HNSW top-10) 0.4 ms Full scan COUNT (no index) ~205 ms GROUP BY (full aggregation) ~273 ms
Point lookups, selective joins, and cached vector search are sub-millisecond; bulk ingest sustains six figures of rows per second thanks to batched group-commit. The honest soft spot is large full-table aggregation — which is exactly what the columnar-OLAP follow-up is for. We keep docs/limitations.md current on purpose: single-writer (inherent to the storage core), in-memory materialization for big joins, and so on. No asterisks hidden in the footer.
The philosophy here matters more than any single number: robustness first, then speed. We'd rather ship a correct feature a release later than a fast, subtly-wrong one.
The headline of 0.9.3: AI-native search
Here's the part we're genuinely excited about. As of 0.9.3, ElyraSQL can do hybrid search — fusing keyword relevance and vector similarity — and it can generate embeddings in SQL. Together, that's the core of a RAG application in a single MySQL-compatible file.
1. HYBRID(...) — full-text + vector, fused
The best retrieval systems don't choose between keyword search and semantic search — they combine both. ElyraSQL makes that a first-class primitive:
SELECT id, title,
HYBRID(body, 'data privacy law', embedding, '[0.12, 0.03, ...]') AS score
FROM docs
WHERE lang = 'en' -- your ordinary structured filter still applies
ORDER BY score DESC
LIMIT 10;
Under the hood, HYBRID(text_col, 'query', vec_col, vector):
ranks documents by vector nearest-neighbour (the HNSW index),
ranks them by full-text term relevance (a FULLTEXT index when present, otherwise a scan),
fuses the two rankings with Reciprocal Rank Fusion — so a document that's strong in both signals rises to the top,
honours your WHERE filter and returns the top-LIMIT, exposing the fused relevance as a normal column.
One query. One file. No Elasticsearch, no pgvector, no external reranker, no glue code holding three systems in an uneasy truce.
2. ai_embed('text') — embeddings, right in the query
The other half of RAG is making embeddings. Normally that's a round-trip in your application: call an embedding API, get a vector, pass it to the database. ElyraSQL lets you skip the detour:
-- Generate the query vector inline
SELECT id, title
FROM docs
ORDER BY VEC_DISTANCE(embedding, ai_embed('data privacy law'))
LIMIT 10;
-- Populate embeddings at insert time
INSERT INTO docs VALUES (1, 'some text', ai_embed('some text'));
-- ...and the two features compose beautifully:
SELECT id, HYBRID(body, 'privacy', embedding, ai_embed('privacy')) AS score
FROM docs ORDER BY score DESC LIMIT 10;
ai_embed() calls an OpenAI-compatible /v1/embeddings endpoint. That means it works with OpenAI and with a local model server — Ollama, LM Studio, llama.cpp, vLLM — because they all speak the same API. Point it at whatever you like:
ELYRASQL_AI_EMBED_URL=http://localhost:11434/v1/embeddings
ELYRASQL_AI_EMBED_MODEL=nomic-embed-text
elyrasql serve
Each unique text is embedded once (resolved in an async pre-pass and cached), then treated as an ordinary vector literal — so everything downstream is unchanged and fast. And a small but telling detail: we wired the HTTP client with ureq + ring specifically so the static musl aarch64 build keeps working. The unglamorous stuff is where "robust" lives.
The quiet work: it now runs your real tools
0.9.x wasn't only headline features. A lot of this cycle was the deeply unsexy work of compatibility — the difference between "passes my tests" and "runs your actual GUI and your actual ORM." We tested against real MySQL clients and a Rust sqlx driver, and fixed what broke:
LIKE/ILIKEin WHERE (yes, really — a fundamental gap, now closed),numeric/string comparison coercion, so bound parameters match numeric columns,
expressions over aggregates like
ROUND(SUM(x), 2)andSUM(a)/COUNT(*),positional ORDER BY,
VERSION()/DATABASE()/USER()as real functions,the SHOW family and a broad
information_schema(engines, views, routines, triggers, foreign-key metadata…) so tools can draw your whole schema tree,and opt-in prepared-statement column descriptions (
ELYRASQL_STMT_DESCRIBE) so drivers like sqlx can resolve result columns by name.
None of that makes a good demo GIF. All of it is the difference between a toy and a tool.
Try it in about 30 seconds
docker run -d --name elyrasql -p 3307:3307
-v elyra:/var/lib/elyrasql
-e ELYRASQL_USER=root -e ELYRASQL_PASSWORD=secret
ghcr.io/kwhorne/elyrasql:0.9.3
mysql -h 127.0.0.1 -P 3307 -u root -psecret
Or grab a self-contained static binary (x86_64 or aarch64) from the 0.9.3 release — MIT licensed, Ubuntu 24.04+.
Where this is going
ElyraSQL is young, and we say so plainly. It isn't trying to dethrone Postgres for a thousand-connection OLTP monster. It's trying to be the database you reach for first when you're building a modern, AI-shaped application and you'd rather ship than assemble a stack: one MySQL-compatible file that does structured data, vector search, full-text, and embeddings — together.
If that resonates, come kick the tires. Re-run the benchmarks on your own box. Point ai_embed at your local Ollama and build a little hybrid-search demo over your notes. And tell us where it breaks — honestly, that's our favorite kind of feedback.
ElyraSQL 0.9.3 is out now. One file. MySQL on the wire. Fluent in AI. 🦀