如何在 SQL Server Management Studio 中查看查询历史记录
Posted
技术标签:
【中文标题】如何在 SQL Server Management Studio 中查看查询历史记录【英文标题】:How to see query history in SQL Server Management Studio 【发布时间】:2011-07-15 01:18:40 【问题描述】:查询历史是否存储在某些日志文件中?如果是,你能告诉我如何找到他们的位置吗?如果没有,你能给我一些关于如何看它的建议吗?
【问题讨论】:
http://www.ssmstoolspack.com/ 提供一个历史记录窗口,如果这是您所追求的。 【参考方案1】:[因为this question 可能会作为副本关闭。]
如果 SQL Server 尚未重新启动(并且计划尚未被驱逐等),您可能能够在计划缓存中找到该查询。
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 崩溃而丢失了文件,您或许可以在此处找到恢复文件:
C:\Users\<you>\Documents\SQL Server Management Studio\Backup Files\
否则,您将需要使用其他东西来帮助您保存查询历史记录,例如Ed Harper's answer 中提到的 SSMS 工具包 - 尽管它在 SQL Server 2012+ 中不是免费的。或者,您可以设置一些轻量级跟踪,根据您的登录名或主机名过滤(但请为此使用服务器端跟踪,而不是 Profiler)。
正如@Nenad-Zivkovic 所说,加入sys.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;
【讨论】:
也可能有助于加入sys.dm_exec_query_stats
并通过last_execution_time
搜索或订购
不适用于 sql server 2000 而适用于 sql server 2005
@Duraiamuthan 好吧,这个问题是关于 Management Studio 的,所以假设 2005+ 应该是安全的。 2000 没有 Management Studio,它有 Query Analyzer。 2000年也是很多年了。如果您想为 SQL Server 2000 解决此问题,您可能应该提出一个带有该特定版本标记的新问题(如果不存在重复项,我没有检查)。
@AaronBertrand 我的评论是对您回答的补充。它将帮助其他人
@AaronBertrand 你是男人中的神。【参考方案2】:
迟到但希望有用,因为它增加了更多细节……
默认情况下,无法查看在 SSMS 中执行的查询。不过有几种选择。
阅读事务日志——这不是一件容易的事,因为它是专有格式的。但是,如果您需要查看历史上执行的查询(SELECT 除外),这是唯一的方法。
您可以为此使用第三方工具,例如 ApexSQL Log 和 SQL Log Rescue(免费,但仅限 SQL 2000)。在此处查看此线程以获取更多详细信息SQL Server Transaction Log Explorer/Analyzer
SQL Server 探查器 - 如果您只想开始审计并且对之前发生的事情不感兴趣,则最适合。确保您使用过滤器仅选择您需要的交易。否则你很快就会得到大量数据。
SQL Server 跟踪 - 如果您想捕获所有或大部分命令并将它们保存在可以稍后解析的跟踪文件中,则最适合。
触发器——最适合您想要捕获 DML(选择除外)并将它们存储在数据库中的某个位置
【讨论】:
使用标准模板在 SQL Server Profiler (msdn.microsoft.com/en-us/library/ms175047(v=sql.110).aspx) 中创建跟踪文件是监控已执行语句的好方法。【参考方案3】:可以使用系统视图查看查询历史:
-
sys.dm_exec_query_stats
sys.dm_exec_sql_text
sys.dm_exec_query_plan
例如,使用以下查询:
select top(100)
creation_time,
last_execution_time,
execution_count,
total_worker_time/1000 as CPU,
convert(money, (total_worker_time))/(execution_count*1000)as [AvgCPUTime],
qs.total_elapsed_time/1000 as TotDuration,
convert(money, (qs.total_elapsed_time))/(execution_count*1000)as [AvgDur],
total_logical_reads as [Reads],
total_logical_writes as [Writes],
total_logical_reads+total_logical_writes as [AggIO],
convert(money, (total_logical_reads+total_logical_writes)/(execution_count + 0.0)) as [AvgIO],
[sql_handle],
plan_handle,
statement_start_offset,
statement_end_offset,
plan_generation_num,
total_physical_reads,
convert(money, total_physical_reads/(execution_count + 0.0)) as [AvgIOPhysicalReads],
convert(money, total_logical_reads/(execution_count + 0.0)) as [AvgIOLogicalReads],
convert(money, total_logical_writes/(execution_count + 0.0)) as [AvgIOLogicalWrites],
query_hash,
query_plan_hash,
total_rows,
convert(money, total_rows/(execution_count + 0.0)) as [AvgRows],
total_dop,
convert(money, total_dop/(execution_count + 0.0)) as [AvgDop],
total_grant_kb,
convert(money, total_grant_kb/(execution_count + 0.0)) as [AvgGrantKb],
total_used_grant_kb,
convert(money, total_used_grant_kb/(execution_count + 0.0)) as [AvgUsedGrantKb],
total_ideal_grant_kb,
convert(money, total_ideal_grant_kb/(execution_count + 0.0)) as [AvgIdealGrantKb],
total_reserved_threads,
convert(money, total_reserved_threads/(execution_count + 0.0)) as [AvgReservedThreads],
total_used_threads,
convert(money, total_used_threads/(execution_count + 0.0)) as [AvgUsedThreads],
case
when sql_handle IS NULL then ' '
else(substring(st.text,(qs.statement_start_offset+2)/2,(
case
when qs.statement_end_offset =-1 then len(convert(nvarchar(MAX),st.text))*2
else qs.statement_end_offset
end - qs.statement_start_offset)/2 ))
end as query_text,
db_name(st.dbid) as database_name,
object_schema_name(st.objectid, st.dbid)+'.'+object_name(st.objectid, st.dbid) as [object_name],
sp.[query_plan]
from sys.dm_exec_query_stats as qs with(readuncommitted)
cross apply sys.dm_exec_sql_text(qs.[sql_handle]) as st
cross apply sys.dm_exec_query_plan(qs.[plan_handle]) as sp
WHERE st.[text] LIKE '%query%'
可以使用以下脚本查看当前正在运行的查询:
select ES.[session_id]
,ER.[blocking_session_id]
,ER.[request_id]
,ER.[start_time]
,DateDiff(second, ER.[start_time], GetDate()) as [date_diffSec]
, COALESCE(
CAST(NULLIF(ER.[total_elapsed_time] / 1000, 0) as BIGINT)
,CASE WHEN (ES.[status] <> 'running' and isnull(ER.[status], '') <> 'running')
THEN DATEDIFF(ss,0,getdate() - nullif(ES.[last_request_end_time], '1900-01-01T00:00:00.000'))
END
) as [total_time, sec]
, CAST(NULLIF((CAST(ER.[total_elapsed_time] as BIGINT) - CAST(ER.[wait_time] AS BIGINT)) / 1000, 0 ) as bigint) as [work_time, sec]
, CASE WHEN (ER.[status] <> 'running' AND ISNULL(ER.[status],'') <> 'running')
THEN DATEDIFF(ss,0,getdate() - nullif(ES.[last_request_end_time], '1900-01-01T00:00:00.000'))
END as [sleep_time, sec] --Время сна в сек
, NULLIF( CAST((ER.[logical_reads] + ER.[writes]) * 8 / 1024 as numeric(38,2)), 0) as [IO, MB]
, CASE ER.transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'ReadUncommited'
WHEN 2 THEN 'ReadCommited'
WHEN 3 THEN 'Repetable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot'
END as [transaction_isolation_level_desc]
,ER.[status]
,ES.[status] as [status_session]
,ER.[command]
,ER.[percent_complete]
,DB_Name(coalesce(ER.[database_id], ES.[database_id])) as [DBName]
, SUBSTRING(
(select top(1) [text] from sys.dm_exec_sql_text(ER.[sql_handle]))
, ER.[statement_start_offset]/2+1
, (
CASE WHEN ((ER.[statement_start_offset]<0) OR (ER.[statement_end_offset]<0))
THEN DATALENGTH ((select top(1) [text] from sys.dm_exec_sql_text(ER.[sql_handle])))
ELSE ER.[statement_end_offset]
END
- ER.[statement_start_offset]
)/2 +1
) as [CURRENT_REQUEST]
,(select top(1) [text] from sys.dm_exec_sql_text(ER.[sql_handle])) as [TSQL]
,(select top(1) [objectid] from sys.dm_exec_sql_text(ER.[sql_handle])) as [objectid]
,(select top(1) [query_plan] from sys.dm_exec_query_plan(ER.[plan_handle])) as [QueryPlan]
,NULL as [event_info]--(select top(1) [event_info] from sys.dm_exec_input_buffer(ES.[session_id], ER.[request_id])) as [event_info]
,ER.[wait_type]
,ES.[login_time]
,ES.[host_name]
,ES.[program_name]
,cast(ER.[wait_time]/1000 as decimal(18,3)) as [wait_timeSec]
,ER.[wait_time]
,ER.[last_wait_type]
,ER.[wait_resource]
,ER.[open_transaction_count]
,ER.[open_resultset_count]
,ER.[transaction_id]
,ER.[context_info]
,ER.[estimated_completion_time]
,ER.[cpu_time]
,ER.[total_elapsed_time]
,ER.[scheduler_id]
,ER.[task_address]
,ER.[reads]
,ER.[writes]
,ER.[logical_reads]
,ER.[text_size]
,ER.[language]
,ER.[date_format]
,ER.[date_first]
,ER.[quoted_identifier]
,ER.[arithabort]
,ER.[ansi_null_dflt_on]
,ER.[ansi_defaults]
,ER.[ansi_warnings]
,ER.[ansi_padding]
,ER.[ansi_nulls]
,ER.[concat_null_yields_null]
,ER.[transaction_isolation_level]
,ER.[lock_timeout]
,ER.[deadlock_priority]
,ER.[row_count]
,ER.[prev_error]
,ER.[nest_level]
,ER.[granted_query_memory]
,ER.[executing_managed_code]
,ER.[group_id]
,ER.[query_hash]
,ER.[query_plan_hash]
,EC.[most_recent_session_id]
,EC.[connect_time]
,EC.[net_transport]
,EC.[protocol_type]
,EC.[protocol_version]
,EC.[endpoint_id]
,EC.[encrypt_option]
,EC.[auth_scheme]
,EC.[node_affinity]
,EC.[num_reads]
,EC.[num_writes]
,EC.[last_read]
,EC.[last_write]
,EC.[net_packet_size]
,EC.[client_net_address]
,EC.[client_tcp_port]
,EC.[local_net_address]
,EC.[local_tcp_port]
,EC.[parent_connection_id]
,EC.[most_recent_sql_handle]
,ES.[host_process_id]
,ES.[client_version]
,ES.[client_interface_name]
,ES.[security_id]
,ES.[login_name]
,ES.[nt_domain]
,ES.[nt_user_name]
,ES.[memory_usage]
,ES.[total_scheduled_time]
,ES.[last_request_start_time]
,ES.[last_request_end_time]
,ES.[is_user_process]
,ES.[original_security_id]
,ES.[original_login_name]
,ES.[last_successful_logon]
,ES.[last_unsuccessful_logon]
,ES.[unsuccessful_logons]
,ES.[authenticating_database_id]
,ER.[sql_handle]
,ER.[statement_start_offset]
,ER.[statement_end_offset]
,ER.[plan_handle]
,NULL as [dop]--ER.[dop]
,coalesce(ER.[database_id], ES.[database_id]) as [database_id]
,ER.[user_id]
,ER.[connection_id]
from sys.dm_exec_requests ER with(readuncommitted)
right join sys.dm_exec_sessions ES with(readuncommitted)
on ES.session_id = ER.session_id
left join sys.dm_exec_connections EC with(readuncommitted)
on EC.session_id = ES.session_id
where ER.[status] in ('suspended', 'running', 'runnable')
or exists (select top(1) 1 from sys.dm_exec_requests as ER0 where ER0.[blocking_session_id]=ES.[session_id])
此请求显示所有活动请求以及所有明确阻止活动请求的请求。
所有这些和其他有用的脚本都作为SRV 数据库中的表示来实现,该数据库免费分发。 例如,第一个脚本来自视图[inf].[vBigQuery],第二个脚本来自视图[inf].[vRequests]。
查询历史记录也有各种第三方解决方案。 我使用来自Dbeaver 的Query Manager: 和来自SQL Tools 的Query Execution History,它嵌入在SSMS 中:
【讨论】:
【参考方案4】:系统不会以这种方式记录查询。但是,如果您知道要提前执行此操作,则可以使用 SQL Profiler 记录传入的内容并在 Profiler 运行期间跟踪查询。
【讨论】:
是的,使用 SQL Profiler,这是 SSMS“工具”菜单中的第一个选项。这就是我通常使用的。参考。 ***.com/questions/2449634/…【参考方案5】:如果需要,您可以通过SQL Profiler 监控 SQL 查询
【讨论】:
【参考方案6】:正如其他人所指出的,您可以使用 SQL Profiler,但您也可以通过 sp_trace_* 系统存储过程来利用它的功能。例如,这个 SQL sn-p 将(至少在 2000 年;我认为它与 SQL 2008 相同,但您必须仔细检查)捕获所有超过 10 秒的查询的 RPC:Completed
和 SQL:BatchCompleted
事件运行,并将输出保存到一个跟踪文件中,您以后可以在 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 中找到每个跟踪事件、列等的 ID;只需搜索sp_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)
我要谨慎说的唯一一件事 -- 我不知道这会给您的系统带来多少负载;它会添加一些,但“一些”有多大可能取决于您的服务器有多忙。
【讨论】:
有用的代码。仅当我删除“.trc”文件扩展名时它才对我有用。【参考方案7】:SELECT deqs.last_execution_time AS [Time], dest.text AS [Query], dest.*
FROM sys.dm_exec_query_stats AS deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest
WHERE dest.dbid = DB_ID('msdb')
ORDER BY deqs.last_execution_time DESC
这应该会显示运行查询的时间和日期
【讨论】:
【参考方案8】:我使用以下查询来跟踪未启用跟踪分析器的 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())
【讨论】:
【参考方案9】:如果您使用的是管理工作室,您可以使用“每次保存时自动生成脚本”。 这肯定不是日志记录。 检查是否对您有用.. ;)
【讨论】:
【参考方案10】:如果您感兴趣的查询是间歇性失败的动态查询,您可以在创建动态语句时将 SQL 以及日期时间和用户记录在表中。它将根据具体情况进行,因为它需要进行特定的编程并且需要一点额外的处理时间,所以只针对您最关心的少数查询进行。但是,当您试图找出它每月仅失败一次的原因时,记录执行的特定语句的日志确实会有所帮助。动态查询很难彻底测试,有时您会得到一个无法正常工作的特定输入值,并且在创建 SQL 时执行此日志记录通常是查看所构建的 sql 中具体内容的最佳方式。
【讨论】:
【参考方案11】:一个稍微开箱即用的方法是在 AutoHotKey 中编写一个解决方案。我使用它,它并不完美,但可以工作并且是免费的。本质上,此脚本为 CTRL+SHIFT+R 分配一个热键,这将在 SSMS 中复制选定的 SQL(CTRL+C),保存一个日期戳 SQL 文件,然后执行突出显示的查询 (F5)。如果您不习惯 AHK 脚本,则前导分号是注释。
;CTRL+SHIFT+R to run a query that is first saved off
^+r::
;Copy
Send, ^c
; Set variables
EnvGet, HomeDir, USERPROFILE
FormatTime, DateString,,yyyyMMdd
FormatTime, TimeString,,hhmmss
; Make a spot to save the clipboard
FileCreateDir %HomeDir%\Documents\sqlhist\%DateString%
FileAppend, %Clipboard%, %HomeDir%\Documents\sqlhist\%DateString%\%TimeString%.sql
; execute the query
Send, f5
Return
最大的限制是如果您单击“执行”而不是使用键盘快捷键,此脚本将无法运行,并且此脚本不会保存整个文件 - 仅保存选定的文本。但是,您始终可以修改脚本以执行查询,然后在复制/保存之前选择所有 (CTRL+A)。
使用具有“在文件中查找”功能的现代编辑器,您可以搜索 SQL 历史记录。您甚至可以花点时间将文件抓取到 SQLite3 数据库中以查询您的查询。
【讨论】:
【参考方案12】:我将我面前的所有答案都归功于我。
此脚本展示了如何找到影响 SQL 的前 20 个'最慢'查询
select top 20 dest.text, deqs.execution_count, deqs.total_elapsed_time, deqs.total_worker_time,
(deqs.total_elapsed_time / deqs.execution_count) as 'avg_elapse_time',
(deqs.total_worker_time / deqs.execution_count) as 'avg_worker_time'
from sys.dm_exec_query_stats as deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) as dest
where deqs. last_execution_time >= '2021-09-27 16:00' /* YOUR DATE AND TIME HERE*/
order by 'avg_elapse_time' desc
【讨论】:
【参考方案13】:如果您想要通过 SMSS 执行的查询的历史记录。
您可能想尝试 SSMSPlus。
https://github.com/akarzazi/SSMSPlus
SSMS 中不存在此功能。
您需要 SSMS 18 或更高版本。
免责声明:我是作者。
【讨论】:
试过了,但它只显示了源自 inside SSMS 的查询。这不是超级有用。我需要来自其他应用的查询。以上是关于如何在 SQL Server Management Studio 中查看查询历史记录的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 SQL Server Management Studio (2008) 在 SQL Server Compact Edition 中创建列
如何在 SQL Server Management Studio 中管理 SQL CE 数据库?
如何在 SQL Server Management Studio 中加入 3 列?
如何在 SQL Server Management Studio 中查看查询历史记录
我用sql server 2008 management studio 连接 sql server 2005, 提示4064错误,请问如何解决?