在构建基于大模型的 Text2SQL 系统时,一个核心挑战是如何让模型准确理解数据库表之间的关联关系。传统方案仅依赖表结构信息(表名、字段名)是远远不够的。当用户提出“查询最近一周的订单及客户信息”这类跨表查询需求时,系统必须知道 t_orders 和 t_customers 表如何关联。缺乏准确的关系信息,将直接导致生成的 SQL 出现缺失关联、错误 JOIN、性能低下甚至执行失败等问题。
围绕这一核心痛点,本文将深入探讨并实践三种主流的表关系(血缘关系)管理方案,分析各自的优劣与适用场景,为技术选型提供切实参考。
一、解决方案整体设计
我们设计的核心思路是:从多个源头自动或半自动提取表关系,存储至图数据库,最终在 SQL 生成阶段将关系信息注入到大模型(LLM)的提示词(Prompt)中。
三种方案全景对比
| 维度 |
方案一:MyBatis自动解析 |
方案二:SQL解析引擎 |
方案三:AntV/X6可视化配置 |
| 实现难度 |
中等 |
高 |
低 |
| 准确性 |
高(基于实际业务代码) |
中(依赖 SQL 日志质量) |
高(人工确认) |
| 维护成本 |
低(自动化) |
中(需定期扫描日志) |
高(完全手动维护) |
| 适用场景 |
使用 MyBatis 的 Java 项目 |
通用 SQL 场景,拥有 SQL 执行日志 |
表数量少、准确性要求高的核心场景 |
| 技术栈 |
Java + Python + Neo4j |
Python + sqlglot + Neo4j |
React + AntV X6 + MySQL + Neo4j |
二、方案一:MyBatis XML 自动解析
此方案适用于拥有大量 MyBatis Mapper XML 文件的 Java 项目,能从真实的业务 SQL 中自动化提取表关联关系。
2.1 整体架构
┌─────────────────┐
│ MyBatis XML │ ← 业务代码中的 SQL
└────────┬────────┘
│ 解析提取
↓
┌─────────────────┐
│ 关系提取器 │ ← 解析 JOIN、WHERE 等
└────────┬────────┘
│ 存储
↓
┌─────────────────┐
│ Neo4j │ ← 图数据库存储表关系
└────────┬────────┘
│ 查询
↓
┌─────────────────┐
│ Text2SQL Agent │ ← 注入关系信息到 Prompt
└─────────────────┘
2.2 核心实现:从 MyBatis 提取关系
我们使用 Python 的 sqlparse 库来解析清理后的 SQL 语句。
解析流程示例:
class MyBatisMapperParser:
"""MyBatis Mapper 文件解析器"""
def parse_sql_statement(self, sql_text: str) -> List[Dict]:
"""解析单条 SQL 语句,提取表关系"""
# 1. 清理 SQL(去除注释、动态标签等)
cleaned_sql = self._clean_sql(sql_text)
# 2. 使用 sqlparse 解析
parsed = sqlparse.parse(cleaned_sql)[0]
# 3. 提取表名
tables = self._extract_tables(parsed)
# 4. 提取 JOIN 关系
relationships = self._extract_join_relationships(parsed, tables)
return relationships
对于如下 MyBatis SQL:
<select id="getOrderWithCustomer">
SELECT o.*, c.name as customer_name
FROM t_orders o
LEFT JOIN t_customers c ON o.customer_id = c.id
WHERE o.create_time >= #{startTime}
</select>
提取出的关系数据为:
{
"from_table": "t_orders",
"to_table": "t_customers",
"field_relation": "t_orders.customer_id=t_customers.id",
"join_type": "LEFT JOIN",
"source_file": "OrderMapper.xml",
"sql_id": "getOrderWithCustomer"
}
2.3 图数据库存储与双写策略
提取的关系数据被存储到 Neo4j 图数据库中,其 Cypher 查询语言能高效处理关联关系。同时,为了兼顾前端可视化编辑和数据可靠性,我们采用了 MySQL 与 Neo4j 双存储策略。
- Neo4j (图结构):用于高效的关联关系查询和图算法分析。
- MySQL (JSON字段):利用其事务特性,便于前端进行可视化关系的编辑、保存和版本管理。
两者的数据通过异步机制保持同步。
2.4 在Text2SQL工作流中注入关系
我们使用 LangGraph 编排 Text2SQL 的完整流程。在“生成 SQL”节点之前,会先查询 Neo4j 获取相关表的关系。
从 Neo4j 查询关系的核心函数:
def get_table_relationship(state: AgentState):
"""查询指定表之间的关系"""
graph = get_neo4j_graph()
table_names = list(state["db_info"].keys())
query = """
MATCH (t1:Table)-[r:REFERENCES]-(t2:Table)
WHERE t1.name IN $table_names
AND t2.name IN $table_names
AND t1.name < t2.name
RETURN
t1.name AS from_table,
r.field_relation AS relationship,
t2.name AS to_table
"""
result = graph.run(query, table_names=table_names).data()
state["table_relationship"] = result
return state
获取的关系信息将被结构化地注入到 LLM 的 Prompt 中,显著提升生成 SQL 的准确率。
三、方案二:通用 SQL 日志解析引擎
对于非 MyBatis 项目或拥有完整 SQL 执行日志的系统,可以使用通用的 SQL 解析引擎 来构建关系图谱。这里我们选用功能强大的 sqlglot 库,它支持多种 SQL 方言。
3.1 核心实现流程
SQL日志 → sqlglot解析 → AST分析 → 关系提取 → Neo4j存储
核心代码示例:
import sqlglot
from sqlglot import parse_one, exp
def extract_table_lineage(sql: str):
ast = parse_one(sql, dialect="mysql")
tables = []
joins = []
# 提取所有表
for table in ast.find_all(exp.Table):
tables.append(table.name)
# 提取JOIN关系
for join in ast.find_all(exp.Join):
left = join.this.name
right = join.args.get("this").name
condition = join.args.get("on")
joins.append({
"left": left,
"right": right,
"condition": str(condition)
})
return tables, joins
3.2 实践要点
| 环节 |
关键点 |
解决方案 |
| SQL收集 |
日志量巨大 |
采样 + 去重 |
| 方言适配 |
多种数据库 |
利用 sqlglot 的多方言支持能力 |
| 关系推断 |
WHERE 中的隐式关联 |
结合字段名相似度进行匹配 |
| 增量更新 |
性能优化 |
定时任务 + 变更检测触发更新 |
四、方案三:AntV/X6 可视化手动配置
当表数量较少,或对核心业务表关系的准确性要求极高时,可采用可视化手动配置方案。使用 AntV X6 图编辑引擎实现拖拽式的表关系编辑。
4.1 功能与数据流转
- 功能:提供画布,支持拖拽创建表节点,通过连接线(Edge)定义关联关系,并标注关联字段。
- 数据流:前端配置数据 → 保存为 JSON → 存储至 MySQL → 异步同步至 Neo4j → 供 Text2SQL 查询使用。
五、方案选型与组合策略建议
5.1 决策矩阵
| 场景 |
推荐方案 |
核心理由 |
| MyBatis/MyBatis-Plus 项目 |
方案一 |
自动化程度高,直接从业务代码提取,维护成本低 |
| 拥有完整SQL日志的多数据源环境 |
方案二 |
通用性强,不依赖特定框架,适配性好 |
| 核心业务表(少于50张) |
方案三 |
准确性要求高,人工配置可控性强 |
| 超大规模表(超过200张) |
方案一 + 方案二 |
自动化构建主体,辅以人工抽样校验 |
5.2 最佳实践:混合方案
在实际项目中,推荐采用分层、混合的策略:
- 基础层(自动化):使用方案一或方案二,自动构建约 80% 的常见表关系。
- 校验层(人工):针对核心、复杂的业务表,使用方案三(可视化)进行人工复核、修正和补充。
- 监控层(持续优化):定期对比自动提取的关系与生产环境 SQL 执行日志,发现遗漏或错误的关系,持续迭代优化提取规则。
六、总结
构建准确的表关系图谱是提升 Text2SQL 系统可靠性的关键一环。三种主流方案各有其适用边界:
- 追求自动化与效率:选择方案一(MyBatis解析)或方案二(SQL解析引擎)。
- 追求极致准确与控制力:选择方案三(可视化配置)。
- 最佳平衡之道:采用 自动化为主、人工校验为辅 的混合模式。
建议从核心业务表开始试点,逐步扩展至全库,形成持续迭代的闭环优化流程。