You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SQL Server中递归查询存储过程与表的数据血缘依赖链

SQL Server数仓对象全链路上游依赖递归追溯方案

适用于存储过程生成数据表、表与存储过程嵌套依赖的数仓环境,解决系统自带DMV仅能返回第一层依赖的问题,支持指定任意存储过程或表作为起点,向上追溯所有上游源表,输出完整依赖链路。

核心实现逻辑

  • 递归终止规则:当分支追溯到不存在任何上游依赖的源表时,自动终止该分支遍历
  • 双向依赖拉取:
    • 遍历到存储过程节点时,调用sys.dm_sql_referenced_entities拉取其引用的所有用户表、存储过程
    • 遍历到用户表节点时,通过sys.sql_modules匹配存储过程定义文本,定位所有生成/写入该表的上游存储过程,继续向上追溯
  • 异常防护:递归过程中记录已遍历的对象路径,遇到重复对象直接跳过,避免循环依赖导致的死递归;同时设置最大递归深度阈值,防止异常场景下查询无限制运行

可直接复用的实现代码

-- 配置追溯起点
DECLARE @StartObject SYSNAME = N'schema.目标对象名'; -- 例:dbo.usp_GenFactSales 或 dbo.FactSales
DECLARE @StartObjectType CHAR(2) = 'P'; -- 起点为存储过程填'P',为用户表填'U'

WITH DependencyChain AS (
    -- 锚点:初始化起点对象
    SELECT
        0 AS DepLevel,
        @StartObject AS ObjectName,
        @StartObjectType AS ObjectType,
        CAST(@StartObject AS NVARCHAR(MAX)) AS DepPath,
        CAST(',' + @StartObject + ',' AS NVARCHAR(MAX)) AS VisitedMark
    UNION ALL
    -- 递归部分:逐层向上遍历
    SELECT
        dc.DepLevel + 1 AS DepLevel,
        ref.ObjectName,
        ref.ObjectType,
        CAST(dc.DepPath + ' -> ' + ref.ObjectName AS NVARCHAR(MAX)) AS DepPath,
        CAST(dc.VisitedMark + ref.ObjectName + ',' AS NVARCHAR(MAX)) AS VisitedMark
    FROM DependencyChain dc
    CROSS APPLY (
        -- 当前节点是存储过程:拉取其引用的表、存储过程
        SELECT
            QUOTENAME(s.name) + '.' + QUOTENAME(o.name) AS ObjectName,
            o.type AS ObjectType
        FROM sys.dm_sql_referenced_entities(dc.ObjectName, 'OBJECT') r
        JOIN sys.objects o ON r.referenced_id = o.object_id
        JOIN sys.schemas s ON o.schema_id = s.schema_id
        WHERE dc.ObjectType = 'P'
          AND o.type IN ('U','P')
          AND r.referenced_schema_name IS NOT NULL
        UNION ALL
        -- 当前节点是表:拉取写入/生成该表的存储过程
        SELECT
            QUOTENAME(s.name) + '.' + QUOTENAME(p.name) AS ObjectName,
            'P' AS ObjectType
        FROM sys.procedures p
        JOIN sys.schemas s ON p.schema_id = s.schema_id
        JOIN sys.sql_modules m ON p.object_id = m.object_id
        WHERE dc.ObjectType = 'U'
          AND (
              m.definition LIKE '%CREATE TABLE ' + REPLACE(dc.ObjectName, QUOTENAME(s.name)+'.', '') + ' %'
              OR m.definition LIKE '%SELECT INTO ' + REPLACE(dc.ObjectName, QUOTENAME(s.name)+'.', '') + ' %'
              OR m.definition LIKE '%INSERT INTO ' + REPLACE(dc.ObjectName, QUOTENAME(s.name)+'.', '') + ' %'
              OR m.definition LIKE '%MERGE ' + REPLACE(dc.ObjectName, QUOTENAME(s.name)+'.', '') + ' %'
          )
    ) ref
    -- 循环依赖检测:已遍历过的对象不再重复处理
    WHERE dc.VisitedMark NOT LIKE '%,' + ref.ObjectName + ',%'
      AND dc.DepLevel < 20 -- 最大递归深度,可根据实际依赖层级调整
)
-- 结果筛选:仅输出最上游源表及完整依赖路径
SELECT DISTINCT
    DepLevel,
    ObjectName AS UpstreamSourceTable,
    DepPath AS FullDependencyLink
FROM DependencyChain
WHERE ObjectType = 'U'
-- 过滤存在上游生成逻辑的中间表
AND ObjectName NOT IN (
    SELECT DISTINCT QUOTENAME(s.name) + '.' + QUOTENAME(t.name)
    FROM sys.tables t
    JOIN sys.schemas s ON t.schema_id = s.schema_id
    JOIN sys.sql_modules m 
        ON m.definition LIKE '%CREATE TABLE ' + QUOTENAME(t.name) + ' %'
        OR m.definition LIKE '%SELECT INTO ' + QUOTENAME(t.name) + ' %'
)
ORDER BY DepLevel, UpstreamSourceTable
OPTION (MAXRECURSION 20); -- 与上述最大递归深度保持一致

使用注意事项

  • 脚本默认不捕获临时表、表变量依赖,如果数仓存储过程大量使用临时表承载中间计算,需要补充对应临时表的关联匹配逻辑
  • 存储过程与表的写入匹配关键词需要和自身数仓开发规范对齐,比如存在TRUNCATE TABLE后写入、分区切换写入等场景,要对应调整sys.sql_modules的匹配规则,避免漏判
  • 存在跨库依赖时,需要在对应业务库下执行脚本,或给对象名补充库名前缀扩展匹配范围
  • 最大递归深度不建议设置超过100,若触发深度阈值报错,优先检查是否存在未被识别的循环依赖,不要盲目拉高阈值

内容的提问来源于stack exchange,提问作者Oaty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:48:31