SQL Server ведёт детальную запись каждого изменения в журнале транзакций. Обычно вы взаимодействуете с ним косвенно — через резервные копии, репликацию или восстановление. Но существует скрытая, недокументированная функция fn_dblog()
, которая позволяет напрямую запрашивать активный журнал транзакций.
Эта функция может помочь вам:
- Расследовать удаления и изменения данных.
- Отслеживать активность DDL и DML.
- Устранять проблемы вроде случайной потери данных.
- Анализировать поведение репликации и восстановления.
Поскольку функция недокументирована, Microsoft её официально не поддерживает и она может измениться без предупреждения. Тем не менее, для администраторов БД и специалистов по расследованию инцидентов это мощный инструмент.
Как работает fn_dblog()
fn_dblog()
раскрывает содержимое активной части журнала транзакций. Базовый синтаксис таков:
SELECT *
FROM fn_dblog(NULL, NULL);
- Два параметра
NULL
указывают SQL Server вывести всё, что сейчас находится в активном журнале. - Можно также передавать LSN (Log Sequence Number), чтобы ограничить диапазон, но для расследований
NULL
обычно достаточно.
Важно: fn_dblog()
работает только с активным журналом. Если журнал был сохранён и усекается (truncated), вы не увидите старые транзакции.
Вывод fn_dblog()
содержит десятки столбцов (в зависимости от версии около 130+), но некоторые особенно полезны:
Столбец | Описание |
---|---|
Operation |
Тип операции журнала (например, LOP_INSERT_ROWS , LOP_DELETE_ROWS , LOP_BEGIN_XACT ). |
Transaction ID |
Идентификатор транзакции. Можно группировать по нему, чтобы увидеть всю транзакцию целиком. |
Context |
Контекст операции (например, LCX_HEAP , LCX_CLUSTERED ). |
AllocUnitName |
Показывает таблицу или индекс, к которым относится операция. |
Transaction Name |
Может включать системные операции вроде CREATE INDEX , DROPOBJ или пользовательские транзакции. |
Begin Time / End Time |
Метки времени начала и окончания транзакции. |
SPID |
Сеанс, сгенерировавший транзакцию. |
Пример запроса для получения данных для конкретной таблицы:
SELECT [Current LSN], Operation, Context, Transaction_ID, AllocUnitName, [Transaction Name]
FROM fn_dblog(NULL, NULL)
WHERE AllocUnitName LIKE '%YourTableName%';
Поиск удалённых данных
Если вы расследуете случайные удаления, fn_dblog()
поможет определить кто, что и когда удалил.
SELECT [Current LSN], Operation, Context, AllocUnitName, [Transaction Name], [Begin Time], [End Time], [SPID]
FROM fn_dblog(NULL, NULL)
WHERE Operation = 'LOP_DELETE_ROWS';
Хотя fn_dblog()
не возвращает напрямую данные удалённой строки, он предоставляет:
- Подробности транзакции
- Задействованную таблицу
- Когда произошло удаление
- Кто это сделал (SPID)
Это поможет вам совместить информацию с восстановлением «до точки во времени» (PITR) или сторонними инструментами для возврата данных.
Исследование активности DDL и DML
Вы также можете отследить:
- Удаления таблиц (
DROPOBJ
) - Перестроения индексов
- Массовые вставки
- Обновления
Пример:
SELECT [Current LSN], Operation, Transaction_ID, AllocUnitName, [Transaction Name]
FROM fn_dblog(NULL, NULL)
WHERE Operation IN ('LOP_DELETE_ROWS', 'LOP_INSERT_ROWS', 'LOP_MODIFY_ROW', 'LOP_DROP_OBJECT');
Это даёт быстрый обзор того, что происходит в базе на уровне журнала.
Фильтрация по транзакции
Если вы нашли подозрительную транзакцию, возьмите её Transaction_ID
и отфильтруйте детали:
SELECT *
FROM fn_dblog(NULL, NULL)
WHERE Transaction_ID = '0000:00001234';
Так вы увидите все записи журнала в рамках этой транзакции и сможете пошагово реконструировать её ход.
Осторожно: недокументировано — значит, не поддерживается
- Microsoft не документирует и не поддерживает
fn_dblog()
. - Поведение может меняться между версиями SQL Server.
- Для запуска требуются права
sysadmin
. - Функция работает только c онлайн‑базами, не с резервными копиями или отсоединёнными файлами журнала (для этого есть
fn_dump_dblog()
).
Продвинутый пример: отслеживание удалений в реальном времени
Можно обернуть fn_dblog()
в задание или процедуру мониторинга для обнаружения удалений:
CREATE TABLE dbo.LogMonitor
(
LSN NVARCHAR(50),
Operation NVARCHAR(50),
AllocUnitName NVARCHAR(255),
TranName NVARCHAR(255),
BeginTime DATETIME,
EndTime DATETIME
);
INSERT INTO dbo.LogMonitor
SELECT [Current LSN], Operation, AllocUnitName, [Transaction Name], [Begin Time], [End Time]
FROM fn_dblog(NULL, NULL)
WHERE Operation = 'LOP_DELETE_ROWS';
После этого можно настраивать оповещения на основе этой таблицы с помощью SQL Agent или собственного мониторинга. Однако, не забывайте, что любая дополнительная нагрузка на журнал транзакций может привести к увеличению времени фиксации транзакций, что чтревато неприятными последствиями.
Практикум для начинающих администраторов: знакомство с fn_dblog()
Небольшая лабораторная работа поможет освоиться пошагово:
- Создайте тестовую таблицу
CREATE TABLE dbo.TestLog ( ID INT IDENTITY(1,1), DataValue NVARCHAR(100) );
- Вставьте пример данных
INSERT INTO dbo.TestLog (DataValue) VALUES ('First'), ('Second'), ('Third');
- Удалите одну строку
DELETE FROM dbo.TestLog WHERE ID = 2;
- Запустите fn_dblog()
SELECT [Current LSN], Operation, AllocUnitName, [Transaction Name], [Begin Time], [End Time] FROM fn_dblog(NULL, NULL) WHERE AllocUnitName LIKE '%TestLog%';
Вы увидите
LOP_DELETE_ROWS
для удалённой записи иLOP_INSERT_ROWS
для вставок. - Определите Transaction ID и повторно выполните запрос, отфильтровав по нему, чтобы увидеть все записи журнала в рамках этой транзакции.
Комментариев нет:
Отправить комментарий