如何找出C#数据层代码未调用的SQL Server存储过程?
找出SQL Server里没被C#应用调用的存储过程
因为staging环境的dm_exec_procedure_stats统计不准,给你几个靠谱的办法:
1. 扫描C#代码库抓取所有调用的存储过程
直接遍历项目里的所有C#文件,把代码里调用的存储过程全列出来,再和数据库里的对比,就能找出没被调用的。
- 用IDE全局搜索关键词:比如
CommandType.StoredProcedure、"EXEC "(注意空格),还有Dapper/EF这类ORM调用存储过程的写法,比如Dapper的Execute("ProcName", commandType: CommandType.StoredProcedure),EF的FromSqlRaw("EXEC ProcName")。 - 把搜出来的存储过程名整理成一个列表,然后跑SQL对比:
SELECT name FROM sys.procedures WHERE is_ms_shipped = 0 -- 排除系统存储过程 AND name NOT IN ('ProcA', 'ProcB', 'ProcC') -- 这里放你从代码里整理的存储过程名
2. 用SQL Server跟踪工具捕获实际调用
临时开启跟踪,把应用跑一遍所有业务流程,捕获期间所有被调用的存储过程,再对比数据库列表:
- Extended Events(推荐,性能影响小):建个会话抓
rpc_completed事件,过滤你的数据库名,跑应用后导出数据:
-- 创建会话 CREATE EVENT SESSION [CaptureProcCalls] ON SERVER ADD EVENT sqlserver.rpc_completed( ACTION(sqlserver.sql_text) WHERE (sqlserver.database_name = N'你的数据库名')) ADD TARGET package0.event_file(SET filename=N'C:\Temp\CaptureProcCalls.xel') -- 选个有权限的路径 WITH (STARTUP_STATE=OFF) GO -- 启动会话 ALTER EVENT SESSION [CaptureProcCalls] ON SERVER STATE=START GO -- 跑遍应用所有业务操作后,停止会话 ALTER EVENT SESSION [CaptureProcCalls] ON SERVER STATE=STOP GO -- 查询捕获到的存储过程 SELECT DISTINCT TRIM(SUBSTRING(xed.event_data.value('(event/data[@name="sql_text"]/value)[1]', 'nvarchar(max)'), CHARINDEX(' ', xed.event_data.value('(event/data[@name="sql_text"]/value)[1]', 'nvarchar(max)')) + 1, LEN(xed.event_data.value('(event/data[@name="sql_text"]/value)[1]', 'nvarchar(max)')))) AS ProcName FROM sys.fn_xe_file_target_read_file('C:\Temp\CaptureProcCalls*.xel', NULL, NULL, NULL) AS xe_files CROSS APPLY (SELECT CAST(xe_files.event_data AS XML) AS event_data) AS xed
- 也可以用SQL Server Profiler,选择
RPC:Completed事件,过滤应用程序名,跑一段时间后导出结果,整理出存储过程列表。
3. 检查依赖关系避免误删
先排除被其他数据库对象(比如其他存储过程、视图)依赖的存储过程,别删错了:
SELECT p.name AS 存储过程名, OBJECT_NAME(sed.referencing_id) AS 依赖它的对象 FROM sys.procedures p LEFT JOIN sys.sql_expression_dependencies sed ON p.object_id = sed.referenced_id WHERE sed.referencing_id IS NULL -- 没有其他数据库对象依赖它 AND p.is_ms_shipped = 0 -- 排除系统存储过程
最后提醒
找到疑似未被调用的存储过程后,先备份,然后可以在staging环境把它们设为禁用(比如加个RETURN在开头),跑几天确认没报错再删,避免漏了某些边缘场景的调用。
内容的提问来源于stack exchange,提问作者Chicagoan
相关产品推荐
相关产品推荐

