如何在SQL Server Management Studio中查看查询历史logging

查询历史logging是否存储在某些日志文件中? 如果是的话,你能告诉我如何find他们的位置? 如果没有,你可以给我一些关于如何看待它的build议吗?

[由于这个问题可能会被重复封闭]

如果SQL Server尚未重新启动(并且该计划尚未被驱逐等),则可以在计划caching中find该查询。

SELECT t.[text] FROM sys.dm_exec_cached_plans AS p CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t WHERE t.[text] LIKE N'%something unique about your query%'; 

如果因为Management Studio崩溃而丢失了文件,则可以在这里find恢复文件:

 C:\Users\<you>\Documents\SQL Server Management Studio\Backup Files\ 

否则,你需要使用别的东西来帮助你保存查询历史logging,比如Ed Harper的答案中提到的SSMS工具包 – 尽pipe它在SQL Server 2012+中不是免费的。 或者你可以设置一些轻量级的跟踪过滤你的login名或主机名(但请使用服务器端跟踪,而不是分析器)。


正如@ Nenad-Zivkovic所说,joinsys.dm_exec_query_stats和按last_execution_time命令可能会有帮助:

 SELECT t.[text], s.last_execution_time FROM sys.dm_exec_cached_plans AS p INNER JOIN sys.dm_exec_query_stats AS s ON p.plan_handle = s.plan_handle CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t WHERE t.[text] LIKE N'%something unique about your query%' ORDER BY s.last_execution_time DESC; 

晚一点,但希望有用,因为它增加了更多的细节…

在默认情况下,无法看到在SSMS中执行的查询。 虽然有几个选项。

读取事务日志 – 这是不是一件容易的事情,因为它在专有格式。 但是,如果您需要查看历史执行的查询(除了SELECT),这是唯一的方法。

您可以为此使用第三方工具,例如ApexSQL日志和SQL日志拯救 (仅限于SQL 2000)。 在此查看此线程获取更多详细信息SQL Server事务日志浏览器/分析器

SQL Server分析器 – 如果你只是想开始审计,并且对之前发生的事情不感兴趣,那么最合适。 确保你使用filter来select你所需要的交易。 否则,你将很快得到大量的数据。

SQL Server跟踪 – 如果要捕获全部或大部分命令并将其保存在可以稍后parsing的跟踪文件中,则最适合。

触发器 – 如果您想要捕获DML(select除外)并将其存储在数据库的某处,则最为合适

(免费) SSMS工具包增加了logging执行历史logging等function。

系统不会以这种方式logging查询。 但是,如果您确实希望提前完成此任务,则可以使用SQL事件探查器logging在事件探查器运行期间正在进入的事件并跟踪查询。

正如其他人所指出的,您可以使用SQL事件探查器,但是您也可以通过sp_trace_ *系统存储过程来利用它的function。 例如,这个SQL代码片段(至less2000年;我认为它是相同的SQL 2008,但你必须仔细检查)捕获RPC:CompletedSQL:BatchCompleted所有查询超过10秒的事件运行,并将输出结果保存到一个跟踪文件中,以后可以在SQL分析器中打开它:

 DECLARE @TraceID INT DECLARE @ON BIT DECLARE @RetVal INT SET @ON = 1 exec @RetVal = sp_trace_create @TraceID OUTPUT, 2, N'Y:\TraceFile.trc' print 'This trace is Trace ID = ' + CAST(@TraceID AS NVARCHAR) print 'Return value = ' + CAST(@RetVal AS NVARCHAR) -- 10 = RPC:Completed exec sp_trace_setevent @TraceID, 10, 1, @ON -- Textdata exec sp_trace_setevent @TraceID, 10, 3, @ON -- DatabaseID exec sp_trace_setevent @TraceID, 10, 12, @ON -- SPID exec sp_trace_setevent @TraceID, 10, 13, @ON -- Duration exec sp_trace_setevent @TraceID, 10, 14, @ON -- StartTime exec sp_trace_setevent @TraceID, 10, 15, @ON -- EndTime -- 12 = SQL:BatchCompleted exec sp_trace_setevent @TraceID, 12, 1, @ON -- Textdata exec sp_trace_setevent @TraceID, 12, 3, @ON -- DatabaseID exec sp_trace_setevent @TraceID, 12, 12, @ON -- SPID exec sp_trace_setevent @TraceID, 12, 13, @ON -- Duration exec sp_trace_setevent @TraceID, 12, 14, @ON -- StartTime exec sp_trace_setevent @TraceID, 12, 15, @ON -- EndTime -- Filter for duration [column 13] greater than [operation 2] 10 seconds (= 10,000ms) declare @duration bigint set @duration = 10000 exec sp_trace_setfilter @TraceID, 13, 0, 2, @duration 

您可以从Books Online中find每个跟踪事件,列等的ID; 只需searchsp_trace_create , sp_trace_setevent和sp_trace_setfiler sprocs。 然后您可以如下控制跟踪:

 exec sp_trace_setstatus 15, 0 -- Stop the trace exec sp_trace_setstatus 15, 1 -- Start the trace exec sp_trace_setstatus 15, 2 -- Close the trace file and delete the trace settings 

…其中“15”是跟踪ID(由sp_trace_create报告,上面第一个脚本踢出)。

您可以查看运行的痕迹:

 select * from ::fn_trace_getinfo(default) 

我唯一要谨慎的说 – 我不知道你的系统会有多less负载。 它会增加一些,但“多less”可能取决于服务器的繁忙程度。

如果需要,可以通过SQL Profiler监视SQL查询

我使用下面的查询来跟踪没有启用跟踪分析器的SQL服务器上的应用程序活动。 该方法使用查询存储(SQL Server 2016+)而不是DMV。 这样可以更好地查看历史数据以及更快的查找。 捕获sp_who / sp_whoisactive无法捕获的短时间运行查询是非常有效的。

 /* Adjust script to your needs. Run full script (F5) -> Interact with UI -> Run full script again (F5) Output will contain the queries completed in that timeframe. */ /* Requires Query Store to be enabled: ALTER DATABASE <db> SET QUERY_STORE = ON ALTER DATABASE <db> SET QUERY_STORE (OPERATION_MODE = READ_WRITE, MAX_STORAGE_SIZE_MB = 100000) */ USE <db> /* Select your DB */ IF OBJECT_ID('tempdb..#lastendtime') IS NULL SELECT GETUTCDATE() AS dt INTO #lastendtime ELSE IF NOT EXISTS (SELECT * FROM #lastendtime) INSERT INTO #lastendtime VALUES (GETUTCDATE()) ;WITH T AS ( SELECT DB_NAME() AS DBName , s.name + '.' + o.name AS ObjectName , qt.query_sql_text , rs.runtime_stats_id , p.query_id , p.plan_id , CAST(p.last_execution_time AS DATETIME) AS last_execution_time , CASE WHEN p.last_execution_time > #lastendtime.dt THEN 'X' ELSE '' END AS New , CAST(rs.last_duration / 1.0e6 AS DECIMAL(9,3)) last_duration_s , rs.count_executions , rs.last_rowcount , rs.last_logical_io_reads , rs.last_physical_io_reads , q.query_parameterization_type_desc FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY plan_id, runtime_stats_id ORDER BY runtime_stats_id DESC) AS recent_stats_in_current_priod FROM sys.query_store_runtime_stats ) AS rs INNER JOIN sys.query_store_runtime_stats_interval AS rsi ON rsi.runtime_stats_interval_id = rs.runtime_stats_interval_id INNER JOIN sys.query_store_plan AS p ON p.plan_id = rs.plan_id INNER JOIN sys.query_store_query AS q ON q.query_id = p.query_id INNER JOIN sys.query_store_query_text AS qt ON qt.query_text_id = q.query_text_id LEFT OUTER JOIN sys.objects AS o ON o.object_id = q.object_id LEFT OUTER JOIN sys.schemas AS s ON s.schema_id = o.schema_id CROSS APPLY #lastendtime WHERE rsi.start_time <= GETUTCDATE() AND GETUTCDATE() < rsi.end_time AND recent_stats_in_current_priod = 1 /* Adjust your filters: */ -- AND (s.name IN ('<myschema>') OR s.name IS NULL) UNION SELECT NULL,NULL,NULL,NULL,NULL,NULL,dt,NULL,NULL,NULL,NULL,NULL,NULL, NULL FROM #lastendtime ) SELECT * FROM T WHERE T.query_sql_text IS NULL OR T.query_sql_text NOT LIKE '%#lastendtime%' -- do not show myself ORDER BY last_execution_time DESC TRUNCATE TABLE #lastendtime INSERT INTO #lastendtime VALUES (GETUTCDATE()) 

如果您使用的是pipe理工作室,则可以使用“每次保存时自动生成脚本”。 这当然不是日志logging。 检查是否对你有用..;)

如果您感兴趣的查询是间歇性失败的dynamic查询,则可以在创builddynamic语句时将SQL和date时间以及用户logging在表中。 这将在个案的基础上进行,但因为它需要特定的程序发生,并且需要额外的处理时间,所以只能用于你最关心的几个查询。 但是当你试图找出为什么每个月只能失败一次的时候,执行特定语句的日志可以帮助你。 dynamic查询很难彻底地testing,有时你会得到一个不能工作的特定input值,在创buildSQL的时候做这种日志logging通常是查看所build立的sql中具体内容的最好方法。