# sql-lineage **Repository Path**: songbaibuxiu/sql-lineage ## Basic Information - **Project Name**: sql-lineage - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-24 - **Last Updated**: 2026-09-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SQL 血缘分析平台 输入一段 SQL,解析出**字段级血缘**(哪个字段来自哪个字段)与**表级血缘**,并渲染成可交互的血缘图。 ``` create table ods.users(id int, name string); create table dws.stat(user_id int, user_name string); insert into dws.stat select id, name from ods.users; ``` 解析结果: ``` dws.stat.user_id ← ods.users.id dws.stat.user_name ← ods.users.name ``` --- ## 仓库构成 本仓库是应用层:后端、前端、安装包脚本。 ``` sql-lineage/ ├── sql-tools/ 后端服务(Spring Boot 3.3,JDK 21) ├── sql-tools-vue/ 前端(Vue 3 + AntV G6 + Monaco) ├── release/ 安装包模板(bin / conf / sql) ├── build-release.sh 打安装包 └── ci.sh 应用层校验 ``` 解析与列级血缘不在本仓库内,通过 Maven 依赖引用: - https://gitee.com/songbaibuxiu/superior-sql-parser.git - https://gitee.com/songbaibuxiu/sqlflow.git --- ## 快速开始 ### 环境要求 - JDK 21 - Maven 3.8+ - Node 20+ 与 pnpm(仅前端需要) ### 构建与启动 ```bash # 1. 后端,默认用内嵌 H2,无需任何外部数据库 # 注意:服务不会自动建表,先执行 release/sql/h2/ 下的两个脚本, # 或用安装包里的 bin/init-db.sh(见下节) (cd sql-tools && mvn package -DskipTests && java -jar target/sql-tools-1.0-SNAPSHOT.jar) # 2. 前端 (cd sql-tools-vue && pnpm install && pnpm dev) ``` 启动后: | 地址 | 说明 | |---|---| | | 前端(vite dev server,`/api` 已代理到后端) | | | 接口文档 | | | 健康检查 | ### 校验(`ci.sh`) 本地或流水线用,**校验应用能否通过测试**,不打安装包(打包装用 `./build-release.sh`)。 ```bash ./ci.sh # 全部:后端测试 + 前端构建 ./ci.sh backend # 只跑 sql-tools 的 mvn test ./ci.sh frontend # 只构建前端,并检查产物有没有写死后端地址 ``` 后端会检查实际执行的测试数(默认不少于 100),防止套件被静默跳过却显示成功。 前端会检查 `sql-tools-vue/dist` 里没有硬编码的主机/端口。任一项失败则退出码非 0。 ### 安装包部署 打出可分发的安装包(bin / conf / sql / lib / web / logs): ```bash ./build-release.sh # 产物:dist/sql-lineage-1.0.0.tar.gz ``` 目标机器上只需 JDK 21: ```bash tar zxf sql-lineage-1.0.0.tar.gz && cd sql-lineage-1.0.0 bin/init-db.sh # 建表 + 初始数据(只需一次) bin/start.sh # 默认内嵌 H2,零配置 ``` **表结构由你自己执行脚本来建立和升级,服务不会自动改库。** 升级时机因此完全可控, 不会因为重启就被动改了表。代价是漏执行脚本会启动失败 —— 服务启动时会校验结构与版本,不匹配就拒绝启动并写明该执行哪个文件。 详见安装包里的 `sql/README.md`。 换数据库只需改 `conf/application.yml` 的 `database.type`(`h2` / `mysql` / `postgresql`) 与连接信息,JDBC URL、驱动、建表脚本会自动匹配。 详见安装包内的 `README.md`。 ### 容器化启动 ```bash # 需先按上面第 1、2 步构建出后端 jar docker compose up -d ``` 前端 ,后端 8080。nginx 已把 `/api` 反代到后端,因此前端产物不含任何硬编码地址。 --- ## 试一下 ### 灌一份演示数据(推荐) 新装起来的库是空的,页面上大部分功能没东西可点。跑一次种子脚本即可得到一套 四层数仓(ods → dwd → dws → ads):9 张带中文名和分区列的表、6 段 SQL 解析出的血缘、 以及一张有两个版本的目标表。 ```bash bin/seed-demo.sh # 灌进默认租户/项目 SEED_SECOND_TENANT=1 bin/seed-demo.sh # 顺带建一个租户,用来看隔离效果 ``` 脚本走 REST 接口而不是直接灌 SQL —— 血缘是一张图,边引用的是列的自增 id, 手写 INSERT 既要自己维护这些 id,又要在三种方言里各写一份,稍有不一致就会造出 一张渲染不出来的图。走接口则由解析器自己生成,且三种后端通吃,附带还是一次端到端冒烟测试。 跑完可以直接看: - 表基础信息 `/catalog/tables?schema=dwd&table=dwd_order_detail` - 血缘关系 `/lineage/graph?start=ads.ads_sale_overview` - 全局搜索 `/search`,搜「金额」或「类目」 ### 直接调接口 ```bash curl -X POST http://localhost:8080/api/lineage/analyze \ -H 'Content-Type: application/json' \ -d '{ "dbType": "hive", "isCreateTable": true, "querySql": "create table ods.users(id int, name string);\ncreate table dws.stat(user_id int, user_name string);\ninsert into dws.stat select id, name from ods.users;" }' ``` 带上 `-H 'X-Tenant-Id: 2' -H 'X-Project-Id: 3'` 可以指定租户;不带则落到默认租户。 --- ## 核心概念 ### 元数据从哪来 字段级血缘**需要知道表结构**,否则 `select *` 和不带表前缀的列名无法展开。 元数据来源抽象为 `MetadataProvider`,按优先级串联,前一个查不到才问后一个: ``` SQL 内的 CREATE TABLE → 外部元数据服务(Gravitino) → 从 SQL 结构推断 ``` 全都拿不到的表会出现在响应的 `unresolvedTables` 中,而不是让整个请求失败。 ### 方言能力差异(重要) 支持 13 种方言,但**能力不一致**,实测结论: | 能力 | 结论 | |---|---| | 列级血缘分析 | 13 种方言在拿到表结构后**全部可用** | | 从 SQL 内 DDL 提取表结构 | **trino / presto / sqlserver 不支持** | 那三种方言的 `CREATE TABLE` 会被解析成 `DefaultStatement` 拿不到列, 因此**必须配置外部元数据服务**。调用 `GET /api/dialects` 可查询每种方言的能力位。 ### 数据目录与临时表 表全名恒为三段 **`数据目录.库.表`**,数据目录参与唯一性 —— `hive_prod.ods.orders` 与 `hive_test.ods.orders` 是两张不同的表。 每个项目有且只有一个**默认数据目录**,建表语句里没写目录时就落到它, 因此不存在「没有数据目录」的表。目录在「数据目录」配置页里维护。 SQL 里写两段名(`from ods.orders`)是常态,解析阶段会按默认目录补成三段再入库, `catalog_name` 有 `NOT NULL` 兜底。两边名字对齐后,血缘表才能关联到元数据、 把中文名和表类型带出来。 页面上则相反:属于**默认目录**的表只显示 `ods.orders`,把那一段藏起来 —— 绝大多数表都在默认目录下,每个名字都顶着同样的前缀纯属噪音。 非默认目录仍显示完整的 `hive_prod.ods.orders`,那才是需要区分的场合。 同一个页面配**临时库/表规则**(库名 / 表名 × 通配符 / 正则)。 ETL 的 SQL 会建一堆中间临时表,命中规则的表在血缘图上被**穿透**掉: ```sql create table tmp.bb as select * from source_a; insert into sink_b select * from tmp.bb; ``` | | 结果 | |---|---| | 包含临时表 | `source_a → tmp.bb → sink_b` | | 不含临时表 | `source_a → sink_b`(不是断成两段) | 血缘分析页的开关只影响**看**,**保存一律过滤** —— 库里永远不会存临时表。 > 匹配方式要显式选:`tmp_*` 在通配符下匹配 `tmp_abc`, > 在正则下 `*` 修饰的是前一个字符 `_`,反而**匹配不到** `tmp_abc`。 > 写错不报错、只是默默匹配不上,所以配置页提供了当场试算的入口。 ### 部分失败容忍 多语句脚本中单条语句失败**不影响其余语句**,失败原因通过 `failedStatements` 返回, 不会出现「接口成功但图是空的、用户不知道为什么」的情况。 ### 层级语义 最终产出字段为 `level 0`,每向上游一跳 +1,取**最长路径**。 存在环时会被检测出来,环上的边标记 `cyclic`,并在 `warnings` 中给出提示。 --- ## 文档 | 文档 | 内容 | |---|---| | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | 架构、数据流、关键设计决策 | | [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) | 开发指南、构建顺序、测试、常见问题 | | [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) | 部署、配置项、数据库切换 | | [docs/KNOWN_ISSUES.md](docs/KNOWN_ISSUES.md) | 已知缺陷与限制,每条附最小复现 SQL | | [sql-tools/README.md](sql-tools/README.md) | 后端 API 详细说明 | | `/swagger-ui.html` | 由代码自动生成的接口文档 | ### 演进记录 | 文档 | 内容 | |---|---| | [OPTIMIZATION_PLAN.md](OPTIMIZATION_PLAN.md) | 最初的整体优化方案 | | [PHASE1_REPORT.md](PHASE1_REPORT.md) | 一期(止血)完成报告 | | [PHASE2_PLAN.md](PHASE2_PLAN.md) / [PHASE2_REPORT.md](PHASE2_REPORT.md) | 二期(架构重构)计划与报告 | | [PHASE3_PLAN.md](PHASE3_PLAN.md) / [PHASE3_PROGRESS.md](PHASE3_PROGRESS.md) | 三期(能力升级)计划与进度 | --- ## 当前状态 `sql-tools` 262 通过(H2;另有 6 个 MySQL / PG 集成用例需 `-Dit.*` 开启,含升级脚本对存量数据的改写)。 三期进行中。已完成:血缘持久化的数据模型与多数据库支持(H2 / MySQL / PostgreSQL 三后端共用同一份用例验证)、版本管理、元数据服务接入(Gravitino / dbx)、 自维护元数据目录、七个前端页面,以及租户 / 项目的完整管理面。 数据目录(含默认目录)与临时库表规则的配置页也已就绪。 ## 已知限制 完整清单见 [docs/KNOWN_ISSUES.md](docs/KNOWN_ISSUES.md),其中影响最大的一条: - **函数调用里的限定字段会丢失上游,join + 函数还可能归属到错误的源表**。 `sum(amount)` 正常,`sum(d.amount)` 拿不到上游;join 场景下 `count(order_id)` 可能被算到另一张根本没有该列的表上。暂未修复 —— 写 SQL 时请遵守文档里给出的两条可靠写法 其余: - **trino / presto / sqlserver** 无法从 `CREATE TABLE` 提取表结构,需配置外部元数据服务 - **ClickHouse** 的关键字列表在上游未实现,编辑器补全对 ck 不可用 - **多租户不是安全边界**:没有登录体系,租户仅作数据隔离维度 - 前端 AntV G6 仍为 v4(已停止特性更新),v5 迁移待评估 ## License Apache License 2.0