如何在Microsoft SQL Server 2016(SP1)中简洁捕获并记录所有数据库查询?
嘿,针对你在SQL Server 2016(SP1)上要捕获并记录所有运行查询的需求,我整理了两种实用方案——适合临时场景的简洁实现,以及生产环境的最优解决方案,你可以根据自己的使用场景来选:
一、简洁快速实现(测试/临时排查首选)
如果只是短时间内需要捕获查询,或者在测试环境做验证,SQL Server Profiler是最容易上手的方式,图形化操作零门槛:
- 打开SSMS,连接到目标实例,右键服务器 → 「跟踪」→ 「新建跟踪」
- 在「常规」选项卡选择「空白」模板,切换到「事件选择」页,勾选以下两个核心事件:
SQL:BatchCompleted:捕获所有批量执行的SQL语句(比如直接在SSMS里跑的查询)RPC:Completed:捕获存储过程或远程过程调用
- 可以按需添加额外列,比如
Duration(执行时长)、CPU(CPU占用)、LoginName(执行用户)、DatabaseName(目标库),然后启动跟踪就能实时看到所有执行的查询,还能选择保存到文件或数据库表。
⚠️ 注意:Profiler对服务器性能影响较大(通常会带来10%-30%的开销),绝对不要在高负载生产环境长期运行!
二、生产环境最优解决方案(性能友好,长期运行)
微软官方推荐的轻量级跟踪方案是Extended Events(扩展事件),它的性能开销仅为Profiler的1/5甚至更低(通常在5%以内),完全适合生产环境长期运行:
方式1:SSMS图形化创建(直观易操作)
- 展开服务器 → 「管理」→ 「扩展事件」→ 「会话」→ 「新建会话」
- 选择「空白会话」,给会话起个名字(比如
CaptureAllQueries) - 在「事件」页,添加两个核心事件:
sql_statement_completed:捕获单条SQL语句执行完成的事件rpc_completed:捕获存储过程调用完成的事件
- 切换到「数据列」页,添加你需要追踪的字段,比如
database_name、username、duration、cpu_time、sql_text - 在「存储」页,选择将事件保存到事件文件(性能最优),设置文件大小上限和滚动更新的文件数量,避免磁盘被占满
- 启动会话后,右键会话 → 「查看目标数据」就能实时查看捕获的查询;也可以用T-SQL查询事件文件:
SELECT event_data.value('(event/@name)[1]', 'varchar(50)') AS EventName, event_data.value('(event/@timestamp)[1]', 'datetime2') AS EventTime, event_data.value('(event/data[@name="database_name"]/value)[1]', 'varchar(100)') AS DatabaseName, event_data.value('(event/data[@name="username"]/value)[1]', 'varchar(100)') AS Username, event_data.value('(event/data[@name="sql_text"]/value)[1]', 'nvarchar(max)') AS SQLText FROM (SELECT CAST(event_data AS XML) AS event_data FROM sys.fn_xe_file_target_read_file('C:\XEvents\CaptureAllQueries*.xel', NULL, NULL, NULL)) AS x ORDER BY EventTime DESC;
方式2:T-SQL快速创建(适合自动化/脚本化)
如果需要批量部署或快速创建,直接执行以下脚本即可:
-- 创建扩展事件会话 CREATE EVENT SESSION CaptureAllQueries ON SERVER ADD EVENT sqlserver.rpc_completed( ACTION(sqlserver.database_name, sqlserver.username, sqlserver.sql_text)), ADD EVENT sqlserver.sql_statement_completed( ACTION(sqlserver.database_name, sqlserver.username, sqlserver.sql_text)) ADD TARGET package0.event_file(SET filename=N'C:\XEvents\CaptureAllQueries.xel', max_file_size=(100), max_rollover_files=(5)) WITH (MAX_MEMORY=4096 KB, EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS, MAX_DISPATCH_LATENCY=30 SECONDS, MAX_EVENT_SIZE=0 KB, MEMORY_PARTITION_MODE=NONE, TRACK_CAUSALITY=OFF, STARTUP_STATE=ON); GO -- 启动会话 ALTER EVENT SESSION CaptureAllQueries ON SERVER STATE = START;
这个脚本会创建一个自动启动的会话,将查询记录保存到C:\XEvents目录下,最多保留5个100MB的文件,避免磁盘溢出。
额外补充:非实时查询捕获
如果只是需要查看已经执行过的查询(不需要实时跟踪),可以查询动态管理视图,虽然无法覆盖所有查询(比如执行后被逐出缓存的),但足够满足大部分排查需求:
SELECT DB_NAME(q.dbid) AS DatabaseName, s.login_name, q.text AS SQLText, q.last_execution_time FROM sys.dm_exec_query_stats s CROSS APPLY sys.dm_exec_sql_text(s.sql_handle) q ORDER BY q.last_execution_time DESC;
内容的提问来源于stack exchange,提问作者SnowStorm
相关产品推荐
相关产品推荐

