拓冰建站拓冰建站
首页 / 资讯中心 / 正文

libSQL 向量基准测试工具链:benchtest、anntest 与 blobtest 的实战指南

libSQL 向量基准测试工具链benchtest、anntest 与 blobtest 的实战指南【免费下载链接】libsqllibSQL is a fork of SQLite that is both Open Source, and Open Contributions.项目地址: https://gitcode.com/GitHub_Trending/li/libsql本文围绕 libsql-sqlite3/benchmark 目录下的三套 C 语言基准测试工具展开介绍如何用它们测量向量索引插入/检索性能、ANN 召回率以及 BLOB 读取性能。读完本文你将掌握这些工具的构建方式、SQL 工作负载文件的生成方法以及如何阅读和复现其输出指标并理解其背后的源码实现原理。背景为什么用 C 写基准测试libSQL 在libsql-sqlite3/benchmark/目录中提供了一套刻意用 C 语言编写的基准测试工具benchtest、anntest、blobtest设计意图很直接获得更快的反馈循环——C 编译远比 Rust 构建快改动测试代码后可以立刻重跑。这套工具直接链接到liblibsql.so位于libsql-sqlite3源码树编译产物../.libs/目录因此它们测量的是 libSQLSQLite 分支在向量扩展vector extension下的真实执行路径而不是某种模拟层。在开始之前需要安装 Python 依赖numpy因为workload.py依赖它生成随机向量数据。可以全局安装也可以使用虚拟环境$ python -m venv .env $ source .env/bin/activate $ pip install -r requirements.txt依赖清单见 requirements.txt。构建三个工具编译入口是 Makefile。三个工具分别由anntest、benchtest、blobtest目标编译均以-O2优化、链接../.libs/下的liblibsql.so$ make anntest benchtest blobtest前提是先在libsql-sqlite3根目录执行make生成.libs/目录下的动态库。运行时要通过LD_LIBRARY_PATH../.libs/指定共享库搜索路径。benchtest通用 SQL 工作负载执行器benchtest 是一个通用工具输入一个 SQL 文件和一个数据库文件逐条执行文件中的全部查询并按段落汇总统计信息。SQL 文件可以用workload.py生成也可以手工编写。运行示例$ LD_LIBRARY_PATH../.libs/ ./benchtest queries.sql data.db open queries file at queries.sql open sqlite db at data.db executed simple statement: CREATE TABLE t ( id INTEGER PRIMARY KEY, emb FLOAT32(4) ); executed simple statement: CREATE INDEX t_idx ON t ( libsql_vector_idx(emb) ); prepared statement: INSERT INTO t VALUES ( ?, vector(?) ); inserts (queries.sql): insert: 710.25 micros (avg.), 4 (count) size : 0.2695 MB reads : 1.00 (avg.), 4 (total) writes: 1.00 (avg.), 4 (total) prepared statement: SELECT * FROM vector_top_k(t_idx, vector(?), ?); search (queries.sql): select: 63.25 micros (avg.), 4 (count) size : 0.2695 MB reads : 1.00 (avg.), 4 (total)注意这里vector_top_k(t_idx, vector(?), ?)的索引名t_idx以单引号包裹benchtest 会把字符串字面量识别为参数见下文模板化逻辑。工作负载文件格式SQL 文件按行读取支持两类内容普通语句如CREATE TABLE、CREATE INDEX、PRAGMA直接通过sqlite3_exec执行---分隔符遇到以---开头的行时先执行sqlite3_wal_checkpoint_v2做一次 FULL 检查点随后打印该段落---之后的内容即段落名的累计统计并清零计数。上例中inserts、search段落就是这样划分的。统计项含义对应 benchtest.c 的聚合逻辑输出字段含义统计方式insert/select/delete平均耗时微秒与执行条数用clock()计时按语句类型分别累加size数据库文件当前大小MBstat()取argv[2]文件大小reads/writes平均与累计的读/写计数通过sqlite3_stmt_status(statement, 1025, 1)与(statement, 1026, 1)获取其中sqlite3_stmt_status的1025、1026是 libSQL 扩展的语句级统计位分别对应一次语句执行期间的读写页计数每 100 行进度信息也会输出到 stderr。模板化与预编译benchtest 的核心机制benchtest 之所以能复现预编译 参数绑定的真实场景关键在于 create_query_template 函数只对以INSERT或SELECT开头的语句做模板化其余语句直接执行扫描语句文本把字符串字面量单引号内内容若前面不是idx关键字则视为参数和裸数字替换为?占位符同时记录每个参数的类型0 整数1 文本与偏移生成模板后若与上一次预编译的模板不同则调用sqlite3_prepare_v2重新准备语句并打印prepared statement: ...执行前通过sqlite3_resetsqlite3_clear_bindings复位再按类型调用sqlite3_bind_int或sqlite3_bind_text绑定参数之后按语句前缀分流SELECT循环sqlite3_step直到SQLITE_DONEINSERT/DELETE单次 step其他前缀直接报错退出。这意味着工作量文件里的每条 INSERT/SELECT 都被编译成同一份预编译语句、不同参数的重复执行测出的是纯执行路径的开销与真实应用prepare 一次、执行多次的模式一致。通过 workload.py 生成工作负载workload.py 是 SQL 文件生成器接受生成函数名 参数的调用方式globals()[sys.argv[1]](*sys.argv[2:])。内置五个生成器生成器签名生成内容recall_uniformdim n qdata带libsql_vector_idx索引queries两张表向量元素在[-1,1]均匀分布用于召回率评测recall_normaldim n q同上但数据不建索引向量直接以文本形式插入用作精确查询对照no_vectorsn q无向量索引的基线场景建x(id, value TEXT)表按主键点查bruteforcedim n q建FLOAT32(dim)列、开启 WAL用ORDER BY vector_distance_cos(...) LIMIT 1做暴力精确检索diskanndim n q建FLOAT32(dim)列 libsql_vector_idx索引用vector_top_k做 ANN 检索用法示例$ python workload.py diskann 64 1000 1000 diskann.sqlbruteforce与diskann的差异正是 README 中对比的重点同样是 1000 条插入 1000 条查询暴力检索每条查询要扫描全部行reads 高达 2000000 total而基于向量索引的检索把读放大压缩了几个数量级。Makefile 一键复现Makefile 提供了diskann、bruteforce、no_vectors三个自动化目标内部逻辑相同先生成 SQL、清掉旧test.db、再以LD_LIBRARY_PATH../.libs/运行 benchtest。README 中的完整示例$ basename $(pwd) libsql-sqlite3 $ make # this command will generate libs in the .libs directory $ cd benchmark $ make bruteforce open queries file at bruteforce.sql open sqlite db at test.db executed simple statement: PRAGMA journal_modeWAL; executed simple statement: CREATE TABLE x ( id INTEGER PRIMARY KEY, embedding FLOAT32(64) ); prepared statement: INSERT INTO x VALUES (?, vector(?)); inserts (bruteforce.sql): insert: 46.27 micros (avg.), 1000 (count) size : 0.2695 MB reads : 1.00 (avg.), 1000 (total) writes: 1.00 (avg.), 1000 (total) prepared statement: SELECT id FROM x ORDER BY vector_distance_cos(embedding, vector(?)) LIMIT ?; search (bruteforce.sql): select: 329.32 micros (avg.), 1000 (count) size : 0.2695 MB reads : 2000.00 (avg.), 2000000 (total)从输出可见暴力检索每条查询平均读取 2000 页1000 行数据全部扫描这正是后续diskann场景要解决的核心开销。anntestANN 召回率评测anntest 用于量化近似最近邻ANN检索的质量。它打开一个包含data (id INTEGER PRIMARY KEY, emb FLOAT32(n))和queries (emb FLOAT32(n))两张表的数据库对queries表中的每个向量同时执行你提供的 ANN 查询和精确查询各一次然后计算二者结果集合的重叠比例recall。命令行参数注意注释中拼写为./anntext实际二进制是./anntest$ # ./anntest [db path] [test name (used only for printed stats)] [ann query] [exact query] $ LD_LIBRARY_PATH../.libs/ ./anntest recall_uniform.db 10-recall10 \ SELECT rowid FROM vector_top_k(data_idx, ?, 10) \ SELECT id FROM data ORDER BY vector_distance_cos(emb, ?) LIMIT 10 open sqlite db at recall_uniform.db ready to perform 1000 queries with SELECT rowid FROM vector_top_k(data_idx, ?, 10) ann query and SELECT id FROM data ORDER BY vector_distance_cos(emb, ?) LIMIT 10 exact query 88.91% 10-recall10 (avg.)数据库文件可以先用 benchtest 配合 workload.py 生成$ python workload.py recall_uniform 64 1000 1000 recall_uniform.sql $ LD_LIBRARY_PATH../.libs/ ./benchtest recall_uniform.sql recall_uniform.db注意workload.py的recall_uniform会创建data_idx索引CREATE INDEX data_idx ON data( libsql_vector_idx(emb) );anntest 的 ANN 查询正是走这个索引。召回率的计算方式从 anntest.c 的源码可以看到完整流程预编译三条语句SELECT emb FROM queries取所有查询向量、ANN 查询、精确查询searchVectors把queries表的全部向量读入内存sqlite3_column_blob 拷贝对每个查询向量先searchRows执行 ANN 查询并收集结果 rowid再执行精确查询收集结果 rowid两处都通过sqlite3_bind_blob绑定向量 blobrecall()函数计算重叠率统计精确结果集合中有多少元素出现在 ANN 结果集合中overlap / nExactSize即单条召回率最后对全部查询向量求平均输出X.XX% test name (avg.)。因此调用时的第二个参数如10-recall10只作为统计标签打印实际语义由你传入的 ANN/精确查询共同决定——LIMIT 10的 ANN 结果与LIMIT 10的精确结果的重叠比例就是 recall10。README 示例中 1000 次查询的 10-recall10 平均值为 88.91%这取决于数据分布与索引参数不同数据集结果会不同。blobtest验证 sqlite3_blob_reopen 的读性能收益blobtest 的目标很明确证明sqlite3_blob_reopenAPI 能显著提升 BLOB 读取性能。它在一个临时数据库里创建x (id INTEGER PRIMARY KEY, blob BLOB)表写入指定数量的指定大小 BLOB然后按随机 rowid 反复读取。命令行参数./blobtest [db path] [read|write] [simple|reopen] [rows] [blob size]。README 给出的对比实验$ LD_LIBRARY_PATH../.libs/ ./blobtest blob-read-simple.db read simple 1000 1000 open sqlite db at blob-read-simple.db blob table: ready to prepare blob table: prepared time: 3.76 micros (avg.), 1000 (count) $ LD_LIBRARY_PATH../.libs/ ./blobtest blob-read-reopen.db read reopen 1000 1000 open sqlite db at blob-read-reopen.db blob table: ready to prepare blob table: prepared time: 0.31 micros (avg.), 1000 (count)同样是 1000 行、1000 字节 BLOB、1000 次随机读reopen策略平均耗时 0.31 微秒simple策略 3.76 微秒——相差约 12 倍。从 blobtest.c 的源码可以看清差异根源simple 策略每次读取前调用sqlite3_blob_open打开句柄读完后sqlite3_blob_close关闭循环 1000 次reopen 策略只调用一次sqlite3_blob_openrowid 0随后每次读取前调用sqlite3_blob_reopen(pBlob, rowid)复用同一个句柄循环结束后才sqlite3_blob_close。sqlite3_blob_reopen复用已打开的 BLOB 句柄、免去重新打开/关闭的固定开销因此对反复读取不同行 BLOB的高频场景收益明显。这类优化对向量存储等以 BLOB 形式存放数据的用例有直接参考价值。底层支撑向量函数与向量索引三个工具共同依赖 libSQL 的向量扩展见 vector.c。sqlite3RegisterVectorFunctions注册了一批内置函数其中有vector(...)、vector32、vector64、vector8、vector16、vectorb16、vector1bit按不同元素类型把文本向量解析为内部表示vector_distance_cos(X, Y)与vector_distance_l2(X, Y)分别计算余弦距离与 L2 距离要求两个向量类型与维度一致源码中vectorDistanceFunc会显式校验 type 与 dims且 L2 不支持 float1bit 向量libsql_vector_idx(col)一个关键的无操作no-op标记函数源码注释明确说明它必须是无操作因为 SQLite 在把列值喂给索引前会先对该列应用此函数用于在CREATE INDEX ... ON t(libsql_vector_idx(emb))语法中标记向量列。而 ANN 查询用的vector_top_k是一个虚拟表名定义于 vectorIndexInt.h 中的VECTOR_INDEX_VTAB_NAMEbenchtest/anntest 中SELECT rowid FROM vector_top_k(data_idx, vector(?), 10)这种用法即通过虚拟表机制在data_idx向量索引上执行近似 top-k 检索。小结与扩展阅读libsql-sqlite3/benchmark 提供了一条完整的向量性能评测闭环workload.py生成场景化 SQL →benchtest测量插入/检索耗时与读写页数 →anntest度量 ANN 召回率 →blobtest验证 BLOB 读取优化。由于全部工具直接链接liblibsql.so并复用sqlite3_prepare_v2、sqlite3_stmt_status、sqlite3_blob_*等原生 API结果可以直接反映 libSQL 向量索引的真实执行行为。想深入验证的读者可以继续阅读生成器与 Makefile workload.py、Makefile三个工具的完整实现 benchtest.c、anntest.c、blobtest.c向量函数与索引虚拟表实现 vector.c、vectorIndexInt.h【免费下载链接】libsqllibSQL is a fork of SQLite that is both Open Source, and Open Contributions.项目地址: https://gitcode.com/GitHub_Trending/li/libsql创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门