← Back to skills
extension
Category: Development & EngineeringAPI key requirement unconfirmed

seekdb 全文索引调优

seekdb 全文索引调优:先量后改。用官方 fts_large_bench 建立同机基线,按代码清单定位分词、索引构建与 MATCH 查询的热点,只做语义零变化的改动,并用四项命中数回归锁住正确性。内置前后对比跑分脚本与离线算分推演工具,附三条被实测证伪的优化假设。

personAuthor: Black628hubOpenAPI

seekdb 全文索引调优

面向 seekdb(OceanBase 内核)全文索引的性能调优工作流:先量、再定位、只做可证明的改动、用命中数回归锁住正确性。

何时使用

  • 需要降低 MATCH ... AGAINST 查询延迟、全文索引构建耗时、或 TOKENIZE() 调用耗时
  • 需要在 seekdb 源码树上复现 / 提升 tools/benchmark/fts_large_bench 的分数
  • 需要判断某个"性能优化"是否真的有效、是否改变了检索语义

不适用:单机 OLTP 调参、SQL 改写优化、与全文索引无关的存储引擎调优。

核心原则

  1. 只认同机对比。跨机器的绝对耗时没有意义(同一份代码在不同机器上可以差 8 倍)。任何收益必须来自"同一台机器、同一参数、改动前后"的对比。
  2. 先确认噪声水平。全文索引构建指标在同一机器上波动可达 ±30%~50%,优化幅度小于噪声的改动等于没做。
  3. 语义零变化。只消除"与输入无关的重复工作",绝不改变分词规则、命中集合、评分排序。
  4. 命中数是回归红线。四项 query_*_hits 任何一项变化,本次改动作废。

工作流

第 1 步:建立可比基线

cd <seekdb 仓库根目录>
bash scripts/run_bench.sh before      # 固定参数跑一遍,落盘报告

参数由脚本固定为评测口径:ROWS=20000 BATCH=500 ROUNDS=3000 QUERY_ROUNDS=200 SAMPLES=3 WARMUP=30 SKIP_LOAD=0。 配置不一致时评分脚本会直接拒评。

第 2 步:判断瓶颈落在哪一类

| 现象 | 优先怀疑 | | --- | --- | | tokenize_*_avg_ms 明显高于 select1_avg_ms(纯 SQL 往返地板) | 分词路径的每次调用固定开销(配置解析、分词器/词典重建) | | build_*_sec 换算到"每段文本"后与 tokenize 单次同量级 | 同一个固定开销被文档数放大 | | query_*_avg_ms 与命中数近似线性(约 0.1~0.2 µs/命中) | 逐命中成本,已经很紧,优化空间小 | | query_limit_avg_ms 与全量命中的查询耗时接近 | LIMIT 没有被下推,整表扫描后只取前 N 行 |

第 3 步:按清单定位代码

见 references/bottleneck-checklist.md,按文件:行号逐项核对。清单里的每一条都是"与文本内容无关的重复工作",属于低风险目标。

第 4 步:一次只改一处,每次都要能编译

改完立刻重编、重跑:

bash scripts/run_bench.sh after
bash scripts/run_bench.sh score     # 自动算分 + 校验四项命中数

第 5 步:写清楚结论

提交材料至少包含:瓶颈定位依据(文件:行号 + 代码事实)、改动内容、同机前后对比、正确性论证(为什么分词/命中结果不变)。

已知的高价值目标(按性价比)

| 目标 | 位置 | 性质 | | --- | --- | --- | | 停用词检查的每个 token 分配 + 恒等字符集转换 | src/storage/fts/ob_fts_stop_word.cpp | 恒等变换消除 | | casedown_word 对无可折叠字符仍走 tolower | 同上 | 恒等变换消除 | | tokenize 参数(parser 名 / properties)每次重新解析 | src/sql/engine/expr/ob_expr_tokenize.cpp | 结果缓存(缓存输入解析,非分词结果) | | 每篇文档重建整套 IK 词典 / 分词器 | src/storage/fts/ob_ik_ft_parser.cpp | 只读对象复用 | | 停用词词典构建但匹配逻辑已被注释 | 同上 | 死代码 |

反例:看起来该做、实际不能做

  • 跳过 BM25 打分:need_calc_relevance 恒为 true 看着像浪费,但执行端的过滤依赖同一个表达式,置 false 会让过滤失效、命中数暴涨。
  • 约束全局词典表的锁:单线程基准下这把锁几乎不花时间,改了实测 0 收益。
  • 缓存分词结果:这是把测试文本硬编码进结果,属于作弊;可缓存的只有"与文本无关的配置解析"。

参考

  • references/bottleneck-checklist.md — 逐条瓶颈与证据
  • scripts/run_bench.sh — 前后对比 + 官方算分 + 命中数校验
  • scripts/score_sim.py — 不跑基准就能推演"某项指标改动值多少分"

附:参赛验证行

<!-- OB-S:_Sywm9CfY09IPrFRRWx8PQ -->