02_TiDB 向量搜索深度实战从基础概念到生产部署标签TiDB向量搜索向量数据库Embedding语义搜索RAG生产部署关键词TiDB 向量搜索、VECTOR 数据类型、向量嵌入、余弦相似度、L2 距离、KNN 搜索、向量索引、SQL 向量查询、生产部署、嵌入模型一、为什么传统关键词搜索已经不够用了先来看一个让我深有体会的真实场景。我们的内部知识库里存了大量技术文档用 Elasticsearch 做关键词搜索。同事问数据库怎么处理并发写入冲突搜出来一堆包含数据库、写入关键词的文档但核心答案——《TiDB 乐观事务与悲观事务详解》——一条都没搜到因为这篇文章里恰好没有并发冲突这个组合词。这就是关键词搜索的根本缺陷它理解的是字符串而不是语义。向量搜索解决的正是这个问题——它把文本的含义编码成数学向量通过向量距离来衡量语义相似度。本文从向量搜索的数学原理出发结合 TiDB 的实际技术实现手把手带你从入门到生产部署。二、向量嵌入将意义映射为坐标2.1 嵌入的本质是什么嵌入Embedding是一种将高维稀疏数据文字、图片映射到低维稠密向量空间的技术。通俗地说就是把苹果、“橙子”、香蕉这些词转化为可以计算距离的坐标点。语义相近的内容在向量空间中距离就近。苹果和水果距离近苹果和汽车距离远。向量空间示意简化为2D ^ 水果 | . 苹果 (0.8, 0.9) | . 橙子 (0.7, 0.85) | . 香蕉 (0.75, 0.8) | | | . 汽车 (0.2, 0.1) | . 卡车 (0.15, 0.12) ------------------------- 交通工具实际的嵌入模型输出是几百到几千维的向量维度越高语义表达能力越强但存储和计算开销也越大。主流选择模型维度特点OpenAI text-embedding-3-small1536性价比高通用场景首选OpenAI text-embedding-3-large3072精度高成本较高Jina Embeddings v31024多语言支持中文BGE-m3 (BAAI)1024开源中英文双语强nomic-embed-text768开源轻量2.2 相似度度量三种距离函数的选择余弦相似度Cosine Similarity衡量两个向量的方向差异与向量长度无关。适用于文本语义相似度场景。Cosine Distance 1 - (A·B) / (|A| × |B|) 两向量夹角越小 → 余弦距离越小 → 语义越相似L2 欧氏距离Euclidean Distance衡量两个向量在空间中的实际距离。适用于向量已经归一化、或者需要考虑向量幅度差异的场景。L2 Distance sqrt(Σ(Ai - Bi)²) 距离越小 → 越相似内积Inner Product / Dot Product向量点积与余弦相似度在向量归一化后等价。适用于某些推荐系统场景。Inner Product Σ(Ai × Bi) 值越大 → 越相似注意内积越大越相似与距离相反实战建议文本语义搜索用余弦相似度图像搜索用L2 距离推荐系统用内积。TiDB 三种都支持函数名分别是VEC_COSINE_DISTANCE()、VEC_L2_DISTANCE()、VEC_DIMS()。三、TiDB 向量数据类型详解3.1 VECTOR 类型语法TiDB 提供两种向量数据类型-- 固定维度推荐可建索引embedding VECTOR(768)-- 768维如 BGE-baseembedding VECTOR(1536)-- 1536维如 OpenAI text-embedding-3-smallembedding VECTOR(3072)-- 3072维如 OpenAI text-embedding-3-large-- 可变维度不可建向量索引embedding VECTOR-- 任意维度适合动态场景重要只有固定维度的VECTOR(D)才能创建向量搜索索引。如果你的业务需要向量索引加速超过 100 万条记录时基本都需要必须使用固定维度。3.2 存储格式与空间计算TiDB 的向量以单精度浮点数4字节数组存储。一个 1536 维向量占用1536 × 4 bytes 6144 bytes ≈ 6 KB100 万条记录的向量存储1,000,000 × 6 KB 6 GB仅向量列架构选择同表存储 vs 跨表 JOIN方案A同表存储推荐简单直接 --------------------------------------------- | id | content | embedding | --------------------------------------------- | 1 | TiDB 使用指南... | [0.12, -0.34,...] | | 2 | 向量搜索原理介绍... | [0.87, 0.21,...] | --------------------------------------------- 优点查询简单无需 JOIN 缺点大文本向量列混合存储影响全表扫描性能 方案B跨表 JOIN适合大文本场景 documents 表id, title, full_content原始文档 doc_embeddings 表doc_id, chunk_id, chunk_text, embedding分块向量 优点原始内容与向量分离扫描效率高 缺点查询需要 JOIN代码稍复杂对于单条内容较大10KB的文档建议用方案B避免向量搜索时拖动大文本列。四、核心距离函数与 SQL 实战4.1 建表与数据插入-- 创建知识库文档表同表存储方案CREATETABLEknowledge_base(idINTPRIMARYKEYAUTO_INCREMENT,doc_idVARCHAR(64)NOTNULL,chunk_idINTNOTNULL,titleVARCHAR(500),contentTEXT,categoryVARCHAR(100),embedding VECTOR(1536),-- OpenAI text-embedding-3-smallcreated_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP,INDEXidx_doc_category(doc_id,category));-- 插入数据embedding 以字符串形式传入INSERTINTOknowledge_base(doc_id,chunk_id,title,content,category,embedding)VALUES(doc_001,1,TiDB 向量搜索入门,TiDB 支持存储和检索向量数据适合构建 AI 应用...,技术文档,[0.12, -0.34, 0.87, 0.21, ...]-- 实际为1536维);4.2 执行向量相似度搜索-- 余弦距离搜索值越小越相似范围 [0, 2]SELECTid,title,content,category,VEC_COSINE_DISTANCE(embedding,[0.15, -0.30, 0.90, ...])ASdistanceFROMknowledge_baseORDERBYdistanceASCLIMIT5;-- L2 欧氏距离搜索值越小越相似SELECTid,title,VEC_L2_DISTANCE(embedding,[0.15, -0.30, 0.90, ...])ASl2_distFROMknowledge_baseORDERBYl2_distASCLIMIT5;-- 带业务过滤的混合查询TiDB 的核心优势SELECTid,title,category,VEC_COSINE_DISTANCE(embedding,[0.15, -0.30, 0.90, ...])ASdistanceFROMknowledge_baseWHEREcategory技术文档-- 先过滤类别ANDcreated_at2024-01-01-- 再过滤时间ORDERBYdistanceASCLIMIT10;4.3 向量工具函数-- 获取向量维度SELECTVEC_DIMS(embedding)FROMknowledge_baseLIMIT1;-- 返回: 1536-- 向量转字符串调试用SELECTCAST(embeddingASCHAR)FROMknowledge_baseLIMIT1;-- 返回: [0.12,-0.34,0.87,...]-- 计算两向量的余弦相似度1 - 余弦距离 余弦相似度SELECT1-VEC_COSINE_DISTANCE([1, 0, 0],[0.9, 0.1, 0])AScosine_similarity;-- 返回: 0.9936...五、向量索引生产环境的性能保障5.1 为什么需要向量索引没有索引的向量搜索是全表扫描每次查询都要计算查询向量与表中所有向量的距离时间复杂度 O(N)。100 万条记录每次查询需计算 100 万次距离延迟轻松破秒。向量索引通过近似最近邻ANN算法将查询时间降低到 O(log N) 级别用少量精度损失换取巨大的性能提升。5.2 创建向量索引-- 在 embedding 列上创建向量搜索索引-- 使用余弦距离COSINEALTERTABLEknowledge_baseADDVECTORINDEXidx_embedding_cosine((VEC_COSINE_DISTANCE(embedding)));-- 使用 L2 距离ALTERTABLEknowledge_baseADDVECTORINDEXidx_embedding_l2((VEC_L2_DISTANCE(embedding)));-- 注意一列只能建一种距离类型的向量索引-- 如果需要两种距离要在两列上分别建索引5.3 向量索引使用验证-- 使用 EXPLAIN 验证向量索引是否生效EXPLAINSELECTid,title,VEC_COSINE_DISTANCE(embedding,[0.1, 0.2, ...])ASdistanceFROMknowledge_baseORDERBYdistanceASCLIMIT10;-- 期望看到Access type 包含 annIndex表明向量索引生效5.4 索引配置与性能调优-- 通过 SHOW INDEX 查看向量索引状态SHOWINDEXFROMknowledge_baseWHEREKey_nameidx_embedding_cosine;-- 索引构建进度大表加索引时可查SELECT*FROMinformation_schema.tidb_indexesWHERETABLE_NAMEknowledge_base;生产调优经验维度控制嵌入维度并非越高越好。在满足精度要求的前提下768维往往比3072维快4倍存储省4倍。如果你的任务是中文语义搜索BGE-base-zh768维的效果完全可以接受。预过滤策略如果业务查询有明确的过滤条件如category、time_range先过滤后向量搜索比全量向量搜索后过滤要快得多-- 推荐写法先用索引过滤再向量搜索SELECTid,title,VEC_COSINE_DISTANCE(embedding,$query_vec)ASdistFROMknowledge_baseWHEREcategory产品手册-- 利用 idx_doc_category 过滤ANDstatusactiveORDERBYdistASCLIMIT5;批量插入优化构建知识库时建议先关闭向量索引批量导入数据后再创建索引与 MySQL 全文索引的最佳实践一致。六、Python 实战端到端向量搜索应用6.1 环境准备pipinstallpytidb openai pymysql6.2 完整的 RAG 数据入库流程importopenaiimportpymysqlimportjsonfromtypingimportList# 配置TIDB_CONFIG{host:gateway01.prod.aws.tidbcloud.com,port:4000,user:your_username,password:your_password,database:ai_knowledge_base,ssl:{ca:/path/to/ca.pem}# TiDB Cloud 需要 SSL}openai_clientopenai.OpenAI(api_keyyour_openai_key)defget_embedding(text:str)-List[float]:获取文本嵌入向量responseopenai_client.embeddings.create(modeltext-embedding-3-small,inputtext)returnresponse.data[0].embeddingdefvector_to_sql_string(vec:List[float])-str:将向量转换为 TiDB SQL 格式字符串returnf[{,.join(str(v)forvinvec)}]classKnowledgeBase:def__init__(self):self.connpymysql.connect(**TIDB_CONFIG)definsert_document(self,doc_id:str,title:str,content:str,category:str):插入文档并自动生成向量# 对内容进行分块简单示例生产中用更智能的分块策略chunksself._chunk_text(content,chunk_size500)withself.conn.cursor()ascursor:fori,chunkinenumerate(chunks):embeddingget_embedding(chunk)vec_strvector_to_sql_string(embedding)cursor.execute( INSERT INTO knowledge_base (doc_id, chunk_id, title, content, category, embedding) VALUES (%s, %s, %s, %s, %s, %s) ,(doc_id,i,title,chunk,category,vec_str))self.conn.commit()print(f文档{doc_id}已入库共{len(chunks)}个分块)defsearch(self,query:str,top_k:int5,category:strNone)-List[dict]:向量相似度搜索query_vecget_embedding(query)vec_strvector_to_sql_string(query_vec)# 构建查询 SQLsqlf SELECT id, doc_id, title, content, category, VEC_COSINE_DISTANCE(embedding, {vec_str}) AS distance FROM knowledge_base{WHERE category %sifcategoryelse}ORDER BY distance ASC LIMIT{top_k}withself.conn.cursor(pymysql.cursors.DictCursor)ascursor:ifcategory:cursor.execute(sql,(category,))else:cursor.execute(sql)returncursor.fetchall()def_chunk_text(self,text:str,chunk_size:int500)-List[str]:简单的文本分块按句子边界# 生产环境建议用 langchain.text_splittersentencestext.split(。)chunks[]current_chunkforsentinsentences:iflen(current_chunk)len(sent)chunk_size:current_chunksent。else:ifcurrent_chunk:chunks.append(current_chunk.strip())current_chunksent。ifcurrent_chunk:chunks.append(current_chunk.strip())returnchunksifchunkselse[text]# 使用示例kbKnowledgeBase()# 插入文档kb.insert_document(doc_idtidb_intro_001,titleTiDB 入门指南,contentTiDB 是一款开源的分布式 NewSQL 数据库支持水平扩展...,category技术文档)# 语义搜索resultskb.search(如何做数据库水平扩展,top_k3,category技术文档)forrinresults:print(f[{r[distance]:.4f}]{r[title]}:{r[content][:100]}...)6.3 使用 pytidb SDK 简化开发pytidb 是 TiDB 官方 Python SDK对上述流程做了高度封装frompytidbimportTiDBClientfrompytidb.embeddingsimportEmbeddingFunction# 使用 OpenAI 嵌入函数embedding_fnEmbeddingFunction(model_nametext-embedding-3-small,api_keyyour_openai_key)# 连接数据库dbTiDBClient.connect(hostgateway01.prod.aws.tidbcloud.com,port4000,usernameyour_user,passwordyour_password,databasetest)# 获取或创建表自动管理 embedding 列tabledb.get_table(documents,embedding_fnembedding_fn)# 插入数据自动生成向量table.bulk_insert([{text:TiDB 支持分布式事务,category:数据库},{text:向量搜索基于语义相似度,category:AI},{text:MySQL 兼容的 SQL 语法,category:数据库},])# 向量搜索自动将查询文本转为向量resultstable.search(分布式数据库事务处理).limit(3).to_list()forrinresults:print(f[{r[_distance]:.4f}]{r[text]})七、生产部署注意事项7.1 大规模场景的分布式存储策略当向量数据量超过 1 亿条时需要考虑分片策略-- 使用 SHARD_ROW_ID_BITS 分散写入热点CREATETABLElarge_vector_table(idBIGINTPRIMARYKEYAUTO_INCREMENT,contentTEXT,embedding VECTOR(768))SHARD_ROW_ID_BITS4;-- 16 个分片分散写入压力-- TiDB 8.5 分区表适合按时间分区的向量数据CREATETABLEtime_partitioned_vectors(idBIGINT,contentTEXT,embedding VECTOR(768),created_dateDATE)PARTITIONBYRANGECOLUMNS(created_date)(PARTITIONp2024q1VALUESLESS THAN(2024-04-01),PARTITIONp2024q2VALUESLESS THAN(2024-07-01),PARTITIONp2024q3VALUESLESS THAN(2024-10-01),PARTITIONp2025VALUESLESS THAN(2025-01-01),PARTITIONpmaxVALUESLESS THAN(MAXVALUE));7.2 连接池与批量操作最佳实践# 生产环境使用连接池fromsqlalchemyimportcreate_enginefromsqlalchemy.poolimportQueuePool enginecreate_engine(mysqlpymysql://user:passhost:4000/db?ssl_ca/path/ca.pem,poolclassQueuePool,pool_size20,# 基础连接数max_overflow10,# 最大额外连接数pool_pre_pingTrue,# 自动检测断连pool_recycle3600# 1小时回收连接)# 批量插入向量比逐条插入快 10-50 倍defbatch_insert_vectors(records:list,batch_size:int1000):foriinrange(0,len(records),batch_size):batchrecords[i:ibatch_size]# 批量嵌入减少 API 调用次数texts[r[content]forrinbatch]responseopenai_client.embeddings.create(modeltext-embedding-3-small,inputtexts)embeddings[item.embeddingforiteminresponse.data]# 批量插入 TiDBvalues[(r[doc_id],r[title],r[content],vector_to_sql_string(emb))forr,embinzip(batch,embeddings)]withengine.connect()asconn:conn.execute(INSERT INTO knowledge_base (doc_id, title, content, embedding) VALUES (%s, %s, %s, %s),values)7.3 监控关键指标指标正常范围告警阈值向量搜索 P99 延迟 100ms有索引 500ms嵌入向量写入 QPS取决于 TiKV 节点数写入延迟 1s向量索引构建进度大表可能需要数小时监控而非告警TiKV 存储使用率 70% 80%八、常见坑与解决方案坑 1向量维度不匹配报错Error: vector has 1536 dimensions, does not fit VECTOR(768)原因换了嵌入模型但没有重建表。解决建表时维度与嵌入模型严格对应换模型必须迁移数据。坑 2带向量索引的全表扫描-- 错误写法向量距离在 WHERE 子句中无法用索引SELECTidFROMkbWHEREVEC_COSINE_DISTANCE(embedding,$vec)0.3;-- 正确写法向量距离在 ORDER BY 中配合 LIMITSELECTid,VEC_COSINE_DISTANCE(embedding,$vec)ASdistFROMkbORDERBYdistASCLIMIT10;坑 3大向量列导致 SELECT * 慢向量列占空间大SELECT *会把所有向量数据传输到应用层。生产环境一定要按需选列-- 不好传输所有向量数据SELECT*FROMknowledge_baseORDERBYVEC_COSINE_DISTANCE(...)LIMIT10;-- 好只返回业务字段SELECTid,title,content,VEC_COSINE_DISTANCE(embedding,$vec)ASdistFROMknowledge_baseORDERBYdistLIMIT10;九、总结TiDB 的向量搜索把关系数据库的 SQL 能力和向量相似度计算原生结合是一次真正有意义的技术演进。核心要点总结嵌入模型选择决定了语义表达质量中文场景推荐 BGE 系列或 JinaVECTOR(D) 固定维度是生产部署的基础可变维度不支持向量索引余弦距离适合文本语义L2 距离适合图像场景向量索引是百万级以上数据的必要条件建表时就要规划先过滤后搜索的 SQL 写法能让向量搜索性能提升数倍批量插入比逐条插入性能差距悬殊大批量数据入库必须批量处理下一篇我们将深入 TiDB 全文搜索与混合搜索看如何将关键词精确匹配和语义搜索有机融合构建企业级 RAG 系统。相关资源TiDB Vector Search 官方文档PyTiDB GitHub向量距离函数参考