
作者:玄同765 | 前置依赖:已掌握系列第 2-5 篇的 SQL 语法 / 对话存储 / AI SQL Agent | 核心价值:闭环系列所有知识点、量化加速效果、给出大模型应用专属 SQL 优化方法论
第 2 篇「大模型应用必备 SQL 语法」→ 第 3 篇「SQL+FastAPI 存储对话历史」→ 第 4 篇「SQL+pgvector 实现 RAG 混合检索」→ 第 5 篇「大模型 Agent 实战:AI 自动写 SQL」→ 本篇「SQL 优化(最终篇)」
前序埋点验证:我们在第 5 篇提前创建了103247 条llm_chat_history对话历史表,并通过 AI 生成的统计 SQL 发现核心性能问题:
-- AI生成的慢SQL:查询近30天对话次数Top10用户
SELECT user_id, COUNT(id) AS chat_count FROM llm_chat_history WHERE create_time >= NOW() - INTERVAL '30 days' GROUP BY user_id ORDER BY chat_count DESC LIMIT 10;
-- 优化前执行时间:820ms | 执行计划:全表扫描所有10w+数据!该性能完全不符合大模型应用≤100ms 的响应要求,本篇将从大模型专属场景出发,彻底解决该问题。
大模型应用的 SQL 查询有明确的业务场景边界,无需通用 SQL 优化的冗余方案(如 10w 级数据无需分库分表),只需聚焦3 大类核心查询场景:
大模型场景 | 核心查询需求 | 优化方向 |
|---|---|---|
连续对话 | 按 user_id + 时间查询上下文 | 复合覆盖索引 |
AI 自动查询 | 按时间范围统计对话数据 | 延迟关联 + 索引覆盖 |
RAG 检索 | 混合 SQL + 向量语义检索 | pgvector 索引优化 |
大模型连续对话的核心查询是 **「按 user_id 查询最近 N 条对话」,复用第 2 篇学过的复合覆盖索引 **(将查询字段直接存入索引,避免回表):
-- 【第2篇复合索引语法】索引字段顺序:user_id(过滤性最强)→ create_time(与查询排序一致,DESC)
-- INCLUDE:将对话内容字段存入索引,无需回表
CREATE INDEX idx_chat_user_time ON llm_chat_history (user_id, create_time DESC)
INCLUDE (prompt, answer, model_name);
-- 验证连续对话查询:查询user_123的最近10条对话(第3篇核心场景)
SELECT prompt, answer FROM llm_chat_history WHERE user_id = 'user_123' ORDER BY create_time DESC LIMIT 10;
-- 优化前:380ms → 优化后:22msAI 生成的统计 SQL 需要 **「时间范围过滤→用户分组→次数排序」,创建过滤字段在前、分组字段在后 ** 的复合索引:
-- 【第2篇索引优化规则】过滤字段create_time在前,分组字段user_id在后
CREATE INDEX idx_chat_time_user ON llm_chat_history (create_time DESC, user_id);
-- 验证AI生成的慢SQL:近30天对话次数Top10
-- 优化前:820ms → 优化后:156ms(初步优化,还能更快)AI 生成的 SQL 会默认使用全字段分组,导致回表开销大。我们用延迟关联优化:仅在子查询中过滤索引字段(id/user_id),再关联全表统计,彻底避免回表。
SELECT t.user_id, COUNT(t.id) AS chat_count
FROM (
-- 子查询:仅扫描复合索引idx_chat_time_user,无需回表
SELECT id, user_id FROM llm_chat_history WHERE create_time >= NOW() - INTERVAL '30 days'
) t
GROUP BY t.user_id
ORDER BY chat_count DESC
LIMIT 10;
-- 优化后执行时间:**68ms**(从820ms→68ms,加速12倍!)
-- 执行计划验证:仅扫描复合索引idx_chat_time_user,无全表扫描无需手动优化每条 SQL,只需在第 5 篇的 Agent 配置中加入大模型应用专属的 SQL 优化提示词,让 AI自动生成延迟关联 SQL:
# 大模型应用专属SQL优化提示词(适配PostgreSQL)
sql_agent_prompt = """
你是专业的大模型应用SQL工程师,生成的SQL必须符合以下规则:
1. 针对llm_chat_history表的统计查询,**必须使用延迟关联优化**;
2. 优先使用现有索引:idx_chat_user_time、idx_chat_time_user;
3. 禁止全表扫描,禁止使用SELECT *;
4. 生成的SQL需兼容PostgreSQL 15+语法。
"""
# 创建Agent时传入提示词(替换第5篇的agent_kwargs参数)
sql_agent = create_sql_agent(
llm=llm,
toolkit=toolkit,
agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
agent_kwargs={
"prefix": sql_agent_prompt # 加入优化规则
}
)【AI 思考】:需要查询近 30 天对话次数 Top10 用户,使用延迟关联优化,优先用现有索引 idx_chat_time_user... 【AI 生成 SQL】:
SELECT t.user_id, COUNT(t.id) AS chat_count FROM (SELECT id, user_id FROM llm_chat_history WHERE create_time >= NOW() - INTERVAL '30 days') t GROUP BY t.user_id ORDER BY chat_count DESC LIMIT 10;【执行时间】:71ms(与手动优化效果几乎一致!)
针对同一用户短时间内多次请求连续对话上下文的高频场景,用 Redis 缓存最近 N 条对话,彻底避免重复查询数据库:
import redis
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
# Redis连接配置(本地Redis默认端口6379)
redis_client = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)
# 连续对话上下文查询接口(第3篇核心接口)
@app.get("/api/chat/history/{user_id}")
async def get_chat_history(user_id: str, db: Session = Depends(get_db)):
# 1. 先查询Redis缓存(缓存key:chat_history_用户ID)
cache_key = f"chat_history_{user_id}"
cached_history = redis_client.get(cache_key)
if cached_history:
return {
"code": 200,
"message": "查询成功",
"data": eval(cached_history),
"source": "redis_cache"
}
# 2. 查询数据库(使用优化后的复合覆盖索引)
db_history = db.query(ChatHistory.prompt, ChatHistory.answer)\
.filter(ChatHistory.user_id == user_id)\
.order_by(ChatHistory.create_time DESC)\
.limit(10)\
.all()
# 转换为JSON格式
result = [{"prompt": item.prompt, "answer": item.answer} for item in db_history]
# 3. 存入Redis缓存(TTL=3600秒,即1小时的对话上下文有效期)
redis_client.setex(cache_key, 3600, str(result))
return {
"code": 200,
"message": "查询成功",
"data": result,
"source": "postgresql"
}大模型查询场景 | 优化前执行时间 | 优化后执行时间 | 优化手段 |
|---|---|---|---|
连续对话上下文 | 380ms | 22ms | 复合覆盖索引 + Redis 缓存 |
AI 统计查询(Top10) | 820ms | 68ms | 复合索引 + 延迟关联 + AI 自动优化 |
RAG 混合检索 | 450ms | 89ms | pgvector 索引优化(第 4 篇已实现) |
graph LR
A[用户对话请求] --> B[FastAPI后端服务]
B -->|连续对话上下文| C[Redis缓存: 近10条对话]
B -->|新对话存储| D[PostgreSQL: 对话历史表<br/>复合覆盖索引]
B -->|AI智能查询| E[大模型Agent<br/>自动生成优化SQL]
B -->|RAG知识库检索| F[pgvector: 混合SQL+向量索引]
E --> D
F --> D
B -->|返回结果| ATEXT存储长文本、TIMESTAMP WITH TIME ZONE存储时间(避免时区偏移);VECTOR(1536)存储 embedding(适配主流大模型维度);user_id + create_time DESC复合覆盖索引;create_time DESC + user_id复合索引;ALTER/DROP);EXPLAIN分析性能瓶颈;我们用 6 篇博客完成了大模型应用 SQL 的全栈落地闭环:
作者:玄同765 | 系列专栏:CSDN・从零学 SQL + 大模型应用落地