查询历史是否存储在一些日志文件中?如果有,你能告诉我怎么找到他们的位置吗?如果没有,你能给我一些建议吗?
当前回答
我使用下面的查询来跟踪未启用跟踪分析器的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())
其他回答
If the queries you are interested in are dynamic queries that fail intermittently, you could log the SQL and the datetime and user in a table at the time the dynamic statement is created. It would be done on a case-by case basis though as it requires specific programming to happen and it takes a littel extra processing time, so do it only for those few queries you are most concerned about. But having a log of the specific statements executed can really help when you are trying to find out why it fails once a month only. Dynamic queries are hard to thoroughly test and sometimes you get one specific input value that just won't work and doing this logging at the time the SQL is created is often the best way to see what specifically wasn in the sql that was built.
晚一点,但希望有用,因为它增加了更多的细节…
在默认情况下,无法查看在SSMS中执行的查询。不过也有几种选择。
读取事务日志-这不是一件容易的事情,因为它是私有格式。但是,如果您需要查看历史上执行的查询(除了SELECT),这是唯一的方法。
您可以使用第三方工具,如ApexSQL日志和SQL日志救援(免费,但仅限SQL 2000)。查看这个线程的更多细节在这里SQL Server事务日志资源管理器/分析器
SQL Server分析器-最适合如果你只是想开始审计,你不感兴趣之前发生了什么。确保使用筛选器只选择您需要的事务。否则你很快就会得到大量的数据。
SQL Server跟踪—如果您想捕获所有或大部分命令,并将它们保存在跟踪文件中,以便稍后进行解析,则最适合。
触发器—如果您想捕获DML(除了select)并将它们存储在数据库中的某个地方,那么最适合使用它
我使用下面的查询来跟踪未启用跟踪分析器的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())
下面的SQL查询可以显示简单的查询日志:
SELECT last_execution_time, text
FROM sys.dm_exec_query_stats stats
CROSS APPLY sys.dm_exec_sql_text(stats.sql_handle)
ORDER BY last_execution_time
下图是它的样子:
并且,下面的SQL查询可以显示简单的事务查询日志:
SELECT Operation, [Begin Time], [End Time]
FROM fn_dblog(NULL,NULL)
下图是它的样子:
此外,我还不知道SQL查询将简单查询日志和简单事务查询日志显示在一起。
一个稍微开箱即用的方法是在AutoHotKey中编写一个解决方案。我用了这个,它不是完美的,但是有效而且免费。从本质上讲,这个脚本为CTRL+SHIFT+R分配了一个热键,它将复制SSMS (CTRL+C)中所选的SQL,保存一个日期戳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数据库中以查询您的查询。
推荐文章
- 如何在Ruby On Rails中使用NuoDB手动执行SQL命令
- 查询JSON类型内的数组元素
- 确定记录是否存在的最快方法
- 如何配置slf4j-simple
- 获得PostgreSQL数据库中当前连接数的正确查询
- 在SQL选择语句Order By 1的目的是什么?
- MySQL数据库表中的最大记录数
- 如何在Python中记录源文件名称和行号
- 从现有模式生成表关系图(SQL Server)
- 我如何循环通过一组记录在SQL Server?
- MongoDB记录所有查询
- HyperLogLog算法是如何工作的?
- 数据库和模式的区别
- 如何在SQL Server中一次更改多个列
- 如何禁用标准错误流的日志记录?