- MariaDB Vector commit 23ecb6ec89a: native vector search functionality of MariaDB Server
- pgvector commit bb424e96e7: vector similarity search extension for PostgreSQL
- Qdrant 1.5.1, client version 1.5.4: vector database (excluding binary quantization that provided a very poor recall for used datasets)
- RediSearch 2.6.13 commit f966d37: a query and indexing engine for Redis
- Weaviate 3.16.0: vector database
- MNIST — 60,000 vectors of 784 dimensions, rather small.
- Fashion-MNIST — 60,000 vectors of 784 dimensions, supposed to be more difficult than MNIST.
- SIFT — 1,000,000 vectors of 128 dimensions. Much larger, so more difficult to get good results.
- GIST — 1,000,000 vectors of 960 dimensions. Large dataset and long vectors — this is the slowest and the most difficult dataset.
The plots
All plots were created by the ann-benchmarksplot.py tool. It plots the index build time or the qps against the recall. The search is always approximate (“ann” in “ann-benchmarks” means Approximate Nearest Neighbor), and recall shows how close the result is to the exact search. If the recall is 1 — the search is exact. You can roughly think of the recall of 0.99 as when you do SELECT … LIMIT 100, you can have one row which is different from the exact result you would’ve got with a full table scan. Because everything — recall, build time, qps — heavily depends on the index and search parameters, ann-benchmarks automatically tries various combinations of them, as instructed by the configuration file, and selects the best result. Meaning, the qps-vs-recall plot, for example, shows the best qps one could get for a given recall.
Database size
Only mariadb and pgvector algorithms (ann-benchmarks calls vector search implementations algorithms, let’s stick to this terminology) implement a method to estimate the index size. MariaDB Vector creates an index about half the size of what pgvector does — which was expected, because we need two bytes per dimension and pgvector uses four. I couldn’t compare with other vector databases, unfortunately.Indexing time
This is the time from the point when a table is empty, to the point when a vector index is completely built. Many vector databases insert the data first and then build the index. As of today, MariaDB Vector does not support that yet, we build the index slowly, as the data is inserted, row by row. Below are the results for all the four datasets, from easiest to the most difficult. Note how build takes longer, qps drops and recall becomes worse as the amount of data grows. As results tend to crowd near the right end of the plot, I’ll show everything in linear and in logit-log scale to have a better view of close-to-one recalls.MNIST-784-Euclidean:
Fashion-MNIST-784-Euclidean:
SIFT-128-Euclidean:
GIST-960-Euclidean:
Search time
Here ann-benchmarks measures qps — queries per second, the more qps the better. As before, it plots the best qps for a given recall and I’m showing linear and logit-log scales.MNIST-784-Euclidean:
Fashion-MNIST-784-Euclidean:
SIFT-128-Euclidean:
GIST-960-Euclidean:
Concurrency
To see how well a particular vector database scales with concurrent load, I used ann-benchmarks in batch mode. In this mode the python module implementing a particular algorithm (for example, access to MariaDB Server via MariaDB Connector/Python) gets all query vectors at once and sends them to the database in parallel, in multiple connections. The concurrency is set to the number of CPUs. One could expect that with 48 CPUs there would be a significant qps boost. Let’s see if this is, indeed, the case.MNIST-784-Euclidean:
I’m only showing MNIST, because this shouldn’t depend on the dataset.
