特定のことが起こったのか、いつ起こったのか、誰がそのアクションを実行したのかを人々が知りたがっている質問をよく目にします。多くの場合、SQL Serverはこの情報を単独で追跡しません。例えば:
dbo.MyProcedure
を最後に実行したのは誰ですか?dbo.Employees
テーブルのsalary
列を更新したのは誰ですか?dbo.Orders
テーブルを最後にクエリしたのは誰ですか?しかし、SQL Server 行うがデフォルトで一時的に追跡する他のイベントがいくつかあり、次のような質問にネイティブに回答できます。
dbo.EmployeeAuditData
テーブルをいつ削除しましたか?この情報を取得するにはどうすればよいですか?
SQL Serverがデフォルトで追跡する貴重な情報がかなりあります。 SQL Server 2005以降、バックグラウンドで実行される「デフォルトトレース」があり、SQL Server 2008以降、system_health
と呼ばれる拡張イベントセッションが自動的に実行されています。
SQL Serverエラーログ、SQL Serverエージェントログ、Windowsイベントログ、および SQL Server Audit 、 Management Data Warehouse などの追加のログから特定の情報を見つけることもできます。 、 イベント通知 、 DMLトリガー 、 DDLトリガー 、 SCOM/System Center 、独自のサーバー側トレースまたは拡張イベントセッション、またはサードパーティの監視ソリューション( 私の雇用者、SQL Sentry によって作成されたものなど)。オプションで トラブルシューティングを支援するためのいわゆる「ブラックボックストレース」 を有効にすることもできます。
ただし、この投稿では、デフォルトのトレース、拡張イベントセッション、エラーログなど、一般的に最も多くの場所で有効になっていることに焦点を当てます。
sp_configure
を使用して無効にしない限り、デフォルトのトレースは通常、ほとんどのシステムで実行されます。これが有効になっている限り、これは貴重な情報の豊富なソースになることができます。キャプチャされるトレースイベントを次に示します。
DECLARE @TraceID INT;
SELECT @TraceID = id FROM sys.traces WHERE is_default = 1;
SELECT t.EventID, e.name as Event_Description
FROM sys.fn_trace_geteventinfo(@TraceID) t
JOIN sys.trace_events e ON t.eventID = e.trace_event_id
GROUP BY t.EventID, e.name;
sys.trace_columns
に参加して、どのイベントがどのデータを伴うかを確認することで、より詳細な情報を得ることができますが、ここではスキップします。特定のトレースデータを実際にクエリしたときに、何があるかを確認できるためです。イベント。これらは、私のシステムで使用できるイベントです(クエリが一致することを確認するには、クエリを実行する必要がありますが、SQL Server 2019 CTP 2.4を介した同じイベントセットです)。
EventID Event_Description
------- ----------------------------------------------
18 Audit Server Starts And Stops
20 Audit Login Failed
22 ErrorLog
46 Object:Created
47 Object:Deleted
55 Hash Warning
69 Sort Warnings
79 Missing Column Statistics
80 Missing Join Predicate
81 Server Memory Change
92 Data File Auto Grow
93 Log File Auto Grow
94 Data File Auto Shrink
95 Log File Auto Shrink
102 Audit Database Scope GDR Event
103 Audit Schema Object GDR Event
104 Audit Addlogin Event
105 Audit Login GDR Event
106 Audit Login Change Property Event
108 Audit Add Login to Server Role Event
109 Audit Add DB User Event
110 Audit Add Member to DB Role Event
111 Audit Add Role Event
115 Audit Backup/Restore Event
116 Audit DBCC Event
117 Audit Change Audit Event
152 Audit Change Database Owner
153 Audit Schema Object Take Ownership Event
155 FT:Crawl Started
156 FT:Crawl Stopped
164 Object:Altered
167 Database Mirroring State Change
175 Audit Server Alter Trace Event
218 Plan Guide Unsuccessful
デフォルトのトレースはロールオーバーファイルを使用するため、利用可能なデータはこれまでのところにのみ戻ることに注意してください。利用可能なデータの日付範囲は、上記のイベントの数と頻度に依存します。より長い履歴を確実に保持したい場合は、トレースに関連付けられている現在アクティブでないファイルを定期的にアーカイブするジョブを設定できます。
例
質問では、見つけたいくつかの質問をしました。以下は、デフォルトのトレースから特定の情報を取得するためのクエリの例です。
質問:AdventureWorksデータベースで最後に自動拡張が行われたのはいつで、どのくらい時間がかかりましたか?
このクエリは、ログファイルとデータファイルの両方について、AdventureWorksデータベース内のすべてのAutoGrowイベントをプルします。これらは、デフォルトのトレースログファイルに残っています。
DECLARE @path NVARCHAR(260);
SELECT
@path = REVERSE(SUBSTRING(REVERSE([path]),
CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM sys.traces
WHERE is_default = 1;
SELECT
DatabaseName,
[FileName],
SPID,
Duration,
StartTime,
EndTime,
FileType = CASE EventClass WHEN 92 THEN 'Data' ELSE 'Log' END
FROM sys.fn_trace_gettable(@path, DEFAULT)
WHERE EventClass IN (92,93)
AND DatabaseName = N'AdventureWorks'
ORDER BY StartTime DESC;
質問:dbo.EmployeeAuditDataテーブルは誰がいつ削除しましたか?
これにより、DROP
という名前のオブジェクトのEmployeeAuditData
イベントが返されます。テーブルのDROP
イベントのみを検出するようにしたい場合は、フィルターを追加できます:ObjectType = 8277
( 完全なリストはここに記載されています )。検索スペースを特定のデータベースに制限したい場合は、フィルターDatabaseName = N'db_name'
を追加できます。
DECLARE @path NVARCHAR(260);
SELECT
@path = REVERSE(SUBSTRING(REVERSE([path]),
CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM sys.traces
WHERE is_default = 1;
SELECT
LoginName,
HostName,
StartTime,
ObjectName,
TextData
FROM sys.fn_trace_gettable(@path, DEFAULT)
WHERE EventClass = 47 -- Object:Deleted
AND EventSubClass = 1
AND ObjectName = N'EmployeeAuditData'
ORDER BY StartTime DESC;
ここには複雑さがあり、それは非常にエッジのケースですが、とにかく言及することは賢明だと思いました。複数のスキーマを使用していて、複数のスキーマで同じオブジェクト名を持つ可能性がある場合、これがどれであるかを判別することはできません(対応するものがまだ存在しない限り)。 UserAがSchemaB.Tablenameを削除し、UserBがSchemaA.Tablenameを削除したという外部のケースがあります。デフォルトのトレースはオブジェクトのschemaを追跡しません(また、このイベントのTextData
をキャプチャしません)、およびに含まれるObjectID
traceは直接一致には役立ちません(オブジェクトが削除され、存在しなくなったため)。この場合、出力にその列を含めることは、まだ存在する同じ名前のテーブルのコピーに対して相互参照するのに役立つ可能性がありますが、システムがこれほど混乱している場合(またはそのようなコピーがすべて削除されている場合)それでも、誰がテーブルのどのコピーを削除したかを推測するための信頼できる方法ではない可能性があります。
SQL Server 2008のサポート:system_healthセッション(SQLCSSブログ) から、SQL Server 2008および2008 R2のsystem_health
セッションからカリングできるデータのリストは次のとおりです。
system_healthイベントセッション(MSDN)を使用 から、SQL Server 2012ではリストが多少拡張されています(SQL Server 2014でも同じです)。
SQL Server 2016では、さらに2つのイベントがキャプチャされます。
KILL
コマンドを使用してプロセスが強制終了されたとき。(ドキュメントはまだ更新されていません しかし、私はこれらと他の変更をどのように発見するかについてブログに書いています 。
特定のバージョンに適用されるより不可解な構成を取得するには、常に次のクエリを直接実行できますが、名前を解釈して述語を解析し、上記のより自然な言語のリストと一致する必要があります。
SELECT e.package, e.event_id, e.name, e.predicate
FROM sys.server_event_session_events AS e
INNER JOIN sys.server_event_sessions AS s
ON e.event_session_id = s.event_session_id
WHERE s.name = N'system_health'
ORDER BY e.package, e.name;
可用性グループを使用している場合、AlwaysOn_failover
とAlwaysOn_health
の2つの新しいセッションも実行されます。次のクエリを使用して、彼らが収集したデータを確認できます。
SELECT s.name, e.package, e.event_id, e.name, e.predicate
FROM sys.server_event_session_events AS e
INNER JOIN sys.server_event_sessions AS s
ON e.event_session_id = s.event_session_id
WHERE s.name LIKE N'AlwaysOn[_]%'
ORDER BY s.name, e.package, e.name;
これらのイベントセッションは、リングバッファーターゲットを使用してデータを格納するため、バッファープールやプランキャッシュと同様に、古いイベントは段階的に廃止されるため、必ずしも必要な日付範囲からイベントをプルできるとは限りません。
例
質問で私はこの架空の質問を提起しました:
今日、メモリ関連のエラーはいくつ発生しましたか?
以下は、system_health
セッションからこの情報を引き出すことができるサンプルの(おそらくあまり効率的ではない)クエリです。
;WITH src(x) AS
(
SELECT y.query('.')
FROM
(
SELECT x = CONVERT(XML, t.target_data)
FROM sys.dm_xe_sessions AS s
INNER JOIN sys.dm_xe_session_targets AS t
ON s.[address] = t.event_session_address
WHERE s.name = N'system_health'
) AS x
CROSS APPLY x.x.nodes('/RingBufferTarget/event') AS y(y)
)
SELECT
x, ts = CONVERT(DATETIME, NULL), err = CONVERT(INT, NULL)
INTO #blat FROM src;
DELETE #blat WHERE x.value('(/event/@name)[1]', 'varchar(255)') <> 'error_reported';
UPDATE #blat SET ts = x.value('(/event/@timestamp)[1]', 'datetime');
UPDATE #blat SET err = x.value('(/event/data/value)[1]', 'int');
SELECT err, number_of_events = COUNT(*)
FROM #blat
WHERE err IN (17803, 701, 802, 8645, 8651, 8657, 8902)
AND ts >= CONVERT(DATE, CURRENT_TIMESTAMP)
GROUP BY err;
DROP TABLE #blat;
(この例は system_health
セッションでのAmit Banerjeeの紹介ブログ投稿 から大まかに借りています。)
拡張イベント(特定のデータをクエリできる多くの例を含む)の詳細については、Jonathan Kehayiasによる次の31部構成のブログシリーズを参照してください。
https://www.sqlskills.com/blogs/jonathan/an-xevent-a-day-31-days-of-extended-events/
SQL Serverはデフォルトで、現在と最新の6つのエラーログファイルを保持します(ただし これは変更できます )。起動情報(使用中のコアの数、メモリ内のロックページが設定されているかどうか、認証モードなど)や、文書化できるほど深刻なエラーやその他のシナリオ(他の場所ではキャプチャされない)など、多くの情報がそこに保存されます。最近の例の1つは、データベースがオフラインになったときに探している人でした。テキストSetting database option OFFLINE
の最新の7つのエラーログをそれぞれスキャンすることで、これを確認できます。
EXEC sys.sp_readerrorlog 0,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 1,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 2,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 3,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 4,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 5,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 6,1,'Setting database option OFFLINE';
その他の詳細 この最近の回答では について説明しました。また、背景情報 toadworldで および 公式ドキュメントで もあります。
デフォルトでエラーログが追跡する「エラー」の1つのグループは、重要な情報が尾からすぐに落ちる可能性があります-すべての成功したバックアップメッセージです。 トレースフラグ3226を有効にする を使用すると、エラーログがノイズでいっぱいになるのを防ぐことができます。