TiDB 向量搜索实战:2026年用 TiDB 构建 AI 应用完全指南
分布式数据库
2026年,为什么 TiDB 向量搜索是 AI 应用的游戏规则改变者
传统 AI 应用架构有一个痛点:你需要一个关系型数据库存业务数据,还需要一个向量数据库存 Embedding。两套数据库意味着数据同步、一致性维护、运维成本翻倍。
TiDB 8.0+ 引入的向量搜索功能彻底改变了这个局面——一个数据库同时支持 SQL 和向量搜索。你可以在同一个查询中同时做关系型过滤和语义检索,这就是 HTAP + Vector 的威力。
| 特性 | TiDB Vector | Milvus | Pinecone | Weaviate |
|---|---|---|---|---|
| SQL 支持 | 原生 | 无 | 无 | GraphQL |
| 向量搜索 | 原生 | 原生 | 原生 | 原生 |
| 事务支持 | ACID | 有限 | 无 | 有限 |
| HTAP | 是 | 否 | 否 | 否 |
| 部署方式 | 自托管/云 | 自托管/云 | 仅云 | 自托管/云 |
| 混合查询 | SQL+Vector | 标量过滤 | 元数据过滤 | GraphQL过滤 |
| 水平扩展 | 自动 | 手动 | 自动 | 手动 |
| 维度上限 | 16384 | 32768 | 2048 | 65535 |
| 索引类型 | HNSW | IVF/HNSW | 自动 | HNSW |
| 开源 | 是 | 是 | 否 | 是 |
TiDB 8.0+ 向量索引配置
安装和连接
# 安装 TiDB Python 客户端
pip install tidb-vector sqlalchemy pymysql
# 或使用 TiDB Serverless(推荐快速开始)
# 获取连接字符串:https://tidbcloud.com
创建带向量列的表
from sqlalchemy import create_engine, Column, Integer, String, Text
from sqlalchemy.orm import declarative_base, Session
from tidb_vector.sqlalchemy import VectorType
import numpy as np
Base = declarative_base()
class Document(Base):
__tablename__ = "documents"
id = Column(Integer, primary_key=True)
content = Column(Text)
category = Column(String(50))
source = Column(String(100))
embedding = Column(VectorType(1536)) # OpenAI ada-002 维度
# 创建引擎和表
engine = create_engine(
"mysql+pymysql://root:@localhost:4000/testdb",
echo=True
)
Base.metadata.create_all(engine)
创建向量索引
-- 创建 HNSW 向量索引
CREATE VECTOR INDEX idx_doc_embedding ON documents(embedding)
WITH METRIC = 'cosine', DIMENSION = 1536;
-- 查看索引信息
SHOW CREATE TABLE documents;
-- 向量搜索查询
SELECT id, content, category,
vec_cosine_distance(embedding, @query_vector) AS distance
FROM documents
WHERE category = 'tech'
ORDER BY distance
LIMIT 10;
完整 Python 实现:插入、搜索、混合查询
插入向量数据
import openai
from sqlalchemy.orm import Session
client = openai.OpenAI(api_key="sk-xxx")
def get_embedding(text: str) -> list[float]:
response = client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
def insert_documents(session: Session, documents: list[dict]):
for doc in documents:
embedding = get_embedding(doc["content"])
document = Document(
content=doc["content"],
category=doc["category"],
source=doc["source"],
embedding=embedding
)
session.add(document)
session.commit()
# 使用示例
with Session(engine) as session:
docs = [
{"content": "TiDB是分布式HTAP数据库,支持OLTP和OLAP", "category": "database", "source": "docs"},
{"content": "向量搜索通过Embedding实现语义相似度检索", "category": "ai", "source": "docs"},
{"content": "Kubernetes是容器编排平台,用于微服务部署", "category": "devops", "source": "docs"},
{"content": "RAG结合检索和生成,提升LLM回答准确性", "category": "ai", "source": "blog"},
]
insert_documents(session, docs)
向量搜索
from tidb_vector.sqlalchemy import vec_cosine_distance
def vector_search(session: Session, query: str, top_k: int = 10):
query_embedding = get_embedding(query)
results = session.query(
Document.id,
Document.content,
Document.category,
Document.source,
vec_cosine_distance(Document.embedding, query_embedding).label("distance")
).order_by("distance").limit(top_k).all()
return results
# 使用示例
with Session(engine) as session:
results = vector_search(session, "如何实现语义搜索?")
for r in results:
print(f"[{r.category}] {r.content} (distance={r.distance:.4f})")
混合查询:SQL + 向量
这是 TiDB 向量搜索最强大的特性——在同一个查询中结合关系型过滤和语义检索:
def hybrid_search(
session: Session,
query: str,
category: str = None,
source: str = None,
top_k: int = 10
):
query_embedding = get_embedding(query)
q = session.query(
Document.id,
Document.content,
Document.category,
Document.source,
vec_cosine_distance(Document.embedding, query_embedding).label("distance")
)
# 关系型过滤 + 向量排序
if category:
q = q.filter(Document.category == category)
if source:
q = q.filter(Document.source == source)
results = q.order_by("distance").limit(top_k).all()
return results
# 在AI类文档中搜索
with Session(engine) as session:
results = hybrid_search(session, "向量数据库", category="ai")
for r in results:
print(f"[{r.category}|{r.source}] {r.content} (distance={r.distance:.4f})")
RAG 应用:用 TiDB 构建检索增强生成
from openai import OpenAI
class TiDBRAG:
def __init__(self, engine, openai_api_key: str):
self.engine = engine
self.llm_client = OpenAI(api_key=openai_api_key)
def retrieve(self, query: str, top_k: int = 5) -> list[dict]:
with Session(self.engine) as session:
results = vector_search(session, query, top_k)
return [
{"content": r.content, "category": r.category, "distance": r.distance}
for r in results
]
def generate(self, query: str, context: list[dict]) -> str:
context_text = "\n".join([f"[{c['category']}] {c['content']}" for c in context])
prompt = f"""基于以下参考资料回答问题。如果参考资料中没有相关信息,请说明。
参考资料:
{context_text}
问题:{query}
回答:"""
response = self.llm_client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
temperature=0.1
)
return response.choices[0].message.content
def query(self, question: str, top_k: int = 5) -> str:
context = self.retrieve(question, top_k)
answer = self.generate(question, context)
return answer
# 使用示例
rag = TiDBRAG(engine, openai_api_key="sk-xxx")
answer = rag.query("TiDB的向量搜索和Milvus有什么区别?")
print(answer)
与专用向量数据库对比
Milvus 对比
| 维度 | TiDB Vector | Milvus |
|---|---|---|
| 数据模型 | 关系型+向量 | 纯向量 |
| 查询语言 | SQL | SDK/REST |
| 事务 | ACID | 最终一致 |
| 运维复杂度 | 中 | 高 |
| 适用场景 | 业务+AI混合 | 纯向量检索 |
Pinecone 对比
| 维度 | TiDB Vector | Pinecone |
|---|---|---|
| 部署 | 自托管/云 | 仅云 |
| 成本 | 低(开源) | 按量付费 |
| 数据控制 | 完全 | 有限 |
| 混合查询 | SQL+Vector | 元数据过滤 |
| 扩展 | 自动 | 自动 |
5 个常见陷阱
1. 向量维度不匹配
Embedding 模型输出的维度必须与表定义的维度一致。
# 错误:维度不匹配
# 表定义:VectorType(1536) → OpenAI ada-002
# 实际使用:text-embedding-3-small → 1536 ✓
# 实际使用:text-embedding-3-large → 3072 ✗ 会报错
# 解决:创建表时指定正确维度
class DocumentLarge(Base):
__tablename__ = "documents_large"
id = Column(Integer, primary_key=True)
content = Column(Text)
embedding = Column(VectorType(3072)) # 匹配 large 模型
2. 忽略索引创建
没有向量索引时,搜索退化为全表扫描,性能极差。
-- 必须创建向量索引
CREATE VECTOR INDEX idx_embedding ON documents(embedding)
WITH METRIC = 'cosine', DIMENSION = 1536;
-- 验证索引
SHOW INDEX FROM documents;
3. 批量插入未优化
逐条插入效率极低,应使用批量操作。
# 低效:逐条插入
for doc in documents:
session.add(doc)
session.commit() # 每次都提交
# 高效:批量插入
session.bulk_save_objects(documents)
session.commit()
4. 距离度量不一致
插入时和查询时必须使用相同的距离度量(cosine、L2、inner product)。
-- 创建索引时指定 cosine
CREATE VECTOR INDEX idx_emb ON documents(embedding)
WITH METRIC = 'cosine', DIMENSION = 1536;
-- 查询时也必须用 cosine 距离
SELECT *, vec_cosine_distance(embedding, @query) AS dist
FROM documents ORDER BY dist LIMIT 10;
-- 错误:索引用 cosine,查询用 L2
SELECT *, vec_l2_distance(embedding, @query) AS dist -- ✗ 结果不准确
FROM documents ORDER BY dist LIMIT 10;
5. 连接池未配置
高并发下,默认连接池会导致连接耗尽。
from sqlalchemy import create_engine
engine = create_engine(
"mysql+pymysql://root:@localhost:4000/testdb",
pool_size=20,
max_overflow=10,
pool_timeout=30,
pool_recycle=3600,
pool_pre_ping=True
)
10 个错误排查
| # | 错误现象 | 可能原因 | 排查方法 |
|---|---|---|---|
| 1 | 维度不匹配错误 | Embedding维度与表定义不一致 | 检查模型输出维度和VectorType参数 |
| 2 | 搜索结果为空 | 向量索引未创建 | SHOW INDEX FROM documents |
| 3 | 搜索性能极慢 | 缺少向量索引 | 检查HNSW索引是否存在 |
| 4 | 连接超时 | 连接池耗尽 | 调整pool_size和max_overflow |
| 5 | 距离计算异常 | 度量不一致 | 确认索引和查询使用同一度量 |
| 6 | 内存溢出 | 批量插入数据量过大 | 分批插入,每批1000-5000条 |
| 7 | 精度不够 | HNSW参数ef_search太小 | 增大ef_search值 |
| 8 | 插入失败 | 向量包含NaN/Inf | 插入前检查embedding有效性 |
| 9 | 混合查询慢 | 关系型过滤未走索引 | 为过滤列创建B-Tree索引 |
| 10 | 结果排序错误 | 距离和相似度混淆 | cosine距离越小越相似 |
# 通用调试工具
def debug_vector(embedding: list[float]):
arr = np.array(embedding)
print(f"维度: {arr.shape}")
print(f"范数: {np.linalg.norm(arr):.6f}")
print(f"包含NaN: {np.any(np.isnan(arr))}")
print(f"包含Inf: {np.any(np.isinf(arr))}")
print(f"范围: [{arr.min():.6f}, {arr.max():.6f}]")
性能调优建议
-- HNSW 索引参数调优
CREATE VECTOR INDEX idx_doc_embedding ON documents(embedding)
WITH METRIC = 'cosine', DIMENSION = 1536,
EF_CONSTRUCTION = 256, -- 构建时搜索宽度(越大越精确,构建越慢)
M = 16; -- 每层最大连接数(越大越精确,内存越多)
-- 查询时调整 ef_search
SET SESSION tidb_vector_ef_search = 128; -- 默认64,增大提升精度降低速度
| 参数 | 默认值 | 推荐范围 | 说明 |
|---|---|---|---|
| EF_CONSTRUCTION | 64 | 64-256 | 构建精度,越大索引质量越高 |
| M | 16 | 12-48 | 图连接度,越大精度越高内存越多 |
| ef_search | 64 | 64-512 | 查询精度,越大结果越精确速度越慢 |
在线工具推荐
- JSON 格式化:分析向量搜索配置时,使用 /zh-CN/json/format 格式化 JSON
- Base64 编码:处理 Embedding 数据时,使用 /zh-CN/encode/base64 编解码
- 哈希计算:验证数据完整性时,使用 /zh-CN/encode/hash 计算哈希值
总结:TiDB 向量搜索将 SQL 和向量检索统一在一个数据库中,是 2026 年构建 AI 应用的最佳选择之一。它消除了关系型数据库和向量数据库之间的数据同步痛点,支持 ACID 事务 + 语义检索的混合查询。关键实践:确保向量维度匹配、创建 HNSW 索引、使用批量插入、保持度量一致性、配置连接池。对于 RAG 应用,TiDB 的混合查询能力让你可以在语义检索的同时做精确的关系型过滤,这是专用向量数据库难以优雅实现的。
本站提供浏览器本地工具,免注册即可试用 →
#TiDB#向量搜索#向量数据库#语义检索#HTAP#RAG#AI应用#Python