Показаны сообщения с ярлыком Engine. Показать все сообщения
Показаны сообщения с ярлыком Engine. Показать все сообщения

1.12.25

Использование fn_dblog, fn_dump_dblog и восстановление с STOPBEFOREMARK до LSN

Автор: Paul Randal, Using fn_dblog, fn_dump_dblog, and restoring with STOPBEFOREMARK to an LSN

Я уже много писал в блоге о недокументированной функции fn_dblog, в написании которой я помогал (и мне ещё многое предстоит :-)), но вот одна функция, которую я ранее не упоминал в блоге: fn_dump_dblog (хотя я рассказывал о ней на конференциях).

Рассмотрим сценарий: кто-то удалил таблицу, и вы хотите выяснить, когда это произошло и, возможно, кто это сделал. Трассировка по умолчанию также переполнилась, поэтому вы больше не можете получить оттуда информацию об операции DDL.

Если записи журнала транзакций об операции DROP ещё не были очищены из активной части журнала, то вы сможете использовать fn_dblog для поиска нужной информации. Вы даже можете просмотреть неактивную часть журнала, используя трассировочный флаг 2536, который указывает средству чтения журнала игнорировать точку усечения журнала и выводить все возможные записи журнала.

Но что делать, если соответствующие записи журнала больше не существуют в текущем журнале? Они остались только в ваших резервных копиях журнала. Вы могли бы кропотливо восстанавливать резервные копии журнала по несколько секунд, пока не найдёте момент, когда произошло удаление, а затем восстановить данные до этого момента.

Или вы можете сэкономить уйму времени и использовать fn_dump_dblog, которая позволяет извлекать и искать записи журнала непосредственно из файла резервной копии журнала, не восстанавливая базу данных!

Редакция от 15.08.13: Осторожно — Джонатан недавно обнаружил на системе заказчика, которая активно использует эту функцию, что каждый вызов fn_dump_dblog создаёт новый скрытый планировщик SQLOS и до трёх потоков, которые не исчезают (и не используются повторно) до перезапуска сервера. Это ошибка, которую команда разработчиков SQL собирается исправить, теперь, когда мы их предупредили. Используйте с осторожностью.

Редакция от 15.05.15: Ошибка исправлена в SQL Server 2012 SP2 и выше, а также в SQL Server 2014. Исправление не будет перенесено в более ранние версии.

Поиск операции DROP в журнале

Вот пример — я создам таблицу, заполню её, создам резервную копию, а затем удалю её.

USE [master];
GO

CREATE DATABASE [FNDBLogTest];
GO
USE [FNDBLogTest];
GO
SET NOCOUNT ON;
GO

-- Создадим таблицы для работы
CREATE TABLE [ProdTable] (
    [c1] INT IDENTITY,
    [c2] DATETIME DEFAULT GETDATE (),
    [c3] CHAR (25) DEFAULT 'a');

CREATE TABLE [ProdTable2] (
    [c1] INT IDENTITY,
    [c2] DATETIME DEFAULT GETDATE (),
    [c3] CHAR (25) DEFAULT 'a');
GO

INSERT INTO [ProdTable] DEFAULT VALUES;
GO 1000

-- Создадим начальные резервные копии
BACKUP DATABASE [FNDBLogTest] TO DISK = N'D:\SQLskills\FNDBLogTest_Full.bak' WITH INIT;
GO
BACKUP LOG [FNDBLogTest] TO DISK = N'D:\SQLskills\FNDBLogTest_Log1.bak' WITH INIT;
GO

INSERT INTO [ProdTable2] DEFAULT VALUES;
GO 1000

Теперь я удалю таблицу и добавлю ещё несколько записей в журнал:

DROP TABLE [ProdTable];
GO

INSERT INTO [ProdTable2] DEFAULT VALUES;
GO 1000

Теперь как я могу найти момент, когда таблица была удалена?

SELECT
    [Current LSN],
    [Operation],
    [Context],
    [Transaction ID],
    [Description]
FROM
    fn_dblog (NULL, NULL),
    (SELECT
        [Transaction ID] AS [tid]
    FROM
        fn_dblog (NULL, NULL)
    WHERE
        [Transaction Name] LIKE '%DROPOBJ%') [fd]
WHERE
    [Transaction ID] = [fd].[tid];
GO
Current LSN            Operation       Context           Transaction ID Description
---------------------- --------------- ----------------- -------------  --------------------------------
0000009d:0000021e:0001 LOP_BEGIN_XACT  LCX_NULL          0000:00001ff7  DROPOBJ; <сокращено>
0000009d:0000021e:0002 LOP_LOCK_XACT   LCX_NULL          0000:00001ff7
0000009d:0000021e:0003 LOP_LOCK_XACT   LCX_NULL          0000:00001ff7
0000009d:0000021e:0008 LOP_MODIFY_ROW  LCX_IAM           0000:00001ff7
0000009d:0000021e:0009 LOP_MODIFY_ROW  LCX_PFS           0000:00001ff7  Deallocated 0001:0000009b
0000009d:0000021e:000a LOP_MODIFY_ROW  LCX_IAM           0000:00001ff7
0000009d:0000021e:000b LOP_MODIFY_ROW  LCX_PFS           0000:00001ff7  Deallocated 0001:0000009c
0000009d:0000021e:000c LOP_MODIFY_ROW  LCX_IAM           0000:00001ff7
0000009d:0000021e:000d LOP_MODIFY_ROW  LCX_PFS           0000:00001ff7  Deallocated 0001:0000009d
0000009d:0000021e:000e LOP_MODIFY_ROW  LCX_IAM           0000:00001ff7
0000009d:0000021e:000f LOP_MODIFY_ROW  LCX_PFS           0000:00001ff7  Deallocated 0001:0000009e
0000009d:0000021e:0010 LOP_MODIFY_ROW  LCX_IAM           0000:00001ff7
0000009d:0000021e:0011 LOP_MODIFY_ROW  LCX_PFS           0000:00001ff7  Deallocated 0001:0000009f
0000009d:0000021e:0012 LOP_MODIFY_ROW  LCX_PFS           0000:00001ff7  Deallocated 0001:0000009a
0000009d:0000021e:0013 LOP_HOBT_DDL    LCX_NULL          0000:00001ff7  Action 3 on HoBt 0xd:100 <сокращено>
0000009d:0000021e:0014 LOP_DELETE_ROWS LCX_MARK_AS_GHOST 0000:00001ff7
0000009d:0000021e:0032 LOP_LOCK_XACT   LCX_NULL          0000:00001ff7
...сокращено...

Здорово, правда?

Теперь я создам ещё одну резервную копию журнала, которая очистит журнал и будет содержать только что просмотренные записи.

BACKUP LOG [FNDBLogTest] TO DISK = N'D:\SQLskills\FNDBLogTest_Log2.bak' WITH INIT;
GO

Кто выполнил DROP?

Если вы хотите выяснить, кто выполнил команду DROP, найдите поле Transaction SID для записи журнала LOP_BEGIN_XACT транзакции удаления и затем передайте это значение функции SUSER_SNAME(). Всё просто!

Восстановление с использованием STOPBEFOREMARK

LSN для записи журнала LOP_BEGIN_XACT — это точка, до которой мне нужно восстановиться.

Для этого можно просто подставить LSN в параметр STOPBEFOREMARK для команды RESTORE. Параметр задокументирован, но его формат — нет! Как полезно!!

Перед LSN необходимо указать «0x», а формат должен точно соответствовать тому, который возвращает fn_dblog.

Таким образом, последовательность восстановления до момента непосредственно перед удалением будет следующей:

RESTORE DATABASE [FNDBLogTest2]
    FROM DISK = N'D:\SQLskills\FNDBLogTest_Full.bak'
WITH
    MOVE N'FNDBLogTest' TO N'C:\SQLskills\FNDBLogTest2.mdf',
    MOVE N'FNDBLogTest_log' TO N'C:\SQLskills\FNDBLogTest2_log.ldf',
    REPLACE, NORECOVERY;
GO

RESTORE LOG [FNDBLogTest2]
    FROM DISK = N'D:\SQLskills\FNDBLogTest_Log1.bak'
WITH
    NORECOVERY;
GO

RESTORE LOG [FNDBLogTest2]
FROM
    DISK = N'D:\SQLskills\FNDBLogTest_Log2.bak'
WITH
    STOPBEFOREMARK = 'lsn:0x0000009d:0000021e:0001',
    NORECOVERY;
GO

RESTORE DATABASE [FNDBLogTest2] WITH RECOVERY;
GO

И таблица снова существует, прямо перед тем моментом, когда она была удалена. Вы видите, где я использовал сформированную строку LSN в последнем восстановлении журнала.

Использование fn_dump_dblog

Что делать, если записи журнала больше не находятся в текущем журнале? Я могу использовать функцию fn_dump_dblog.

Например, вот как я могу использовать её для просмотра резервной копии FNDBLogTest_Log2.bak:

SELECT
    COUNT (*)
FROM
    fn_dump_dblog (
        NULL, NULL, N'DISK', 1, N'D:\SQLskills\FNDBLogTest_Log2.bak',
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT);
GO

Мне необходимо указать все параметры DEFAULT (их 63!), иначе функция не сработает. Остальные параметры:

  • Начальный LSN (обычно просто NULL)
  • Конечный LSN (опять же, обычно NULL)
  • Тип файла (DISK или TAPE)
  • Номер резервной копии в файле (для наборов носителей с несколькими резервными копиями)
  • Имя файла

Таким образом, я могу выполнить тот же запрос, что и выше:

SELECT
    [Current LSN],
    [Operation],
    [Context],
    [Transaction ID],
    [Description]
FROM
    fn_dump_dblog (
        NULL, NULL, N'DISK', 1, N'D:\SQLskills\FNDBLogTest_Log2.bak',
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT),
    (SELECT
        [Transaction ID] AS [tid]
    FROM
        fn_dump_dblog (
            NULL, NULL, N'DISK', 1, N'D:\SQLskills\FNDBLogTest_Log2.bak',
            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
            DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT)
    WHERE
        [Transaction Name] LIKE '%DROPOBJ%') [fd]
WHERE [Transaction ID] = [fd].[tid];
GO

Что работает отлично, но выполняется гораздо дольше.

Вам, наверное, интересно, для чего нужны все остальные параметры fn_dump_dblog? Они предназначены для указания семейств носителей набора носителей, который имеет более одного семейства носителей.

Вот пример использования резервной копии журнала, распределённой по двум файлам:

BACKUP LOG [FNDBLogTest] TO
    DISK = N'D:\SQLskills\FNDBLogTest_Log3_1.bak',
    DISK = N'D:\SQLskills\FNDBLogTest_Log3_2.bak'
WITH INIT;
GO

Если я попытаюсь использовать fn_dump_dblog и укажу только один файл, я получу ошибку:

SELECT
    COUNT (*)
FROM
    fn_dump_dblog (
        NULL, NULL, N'DISK', 1, N'D:\SQLskills\FNDBLogTest_Log3_1.bak',
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT);
GO
Msg 3132, Level 16, State 1, Line 1
The media set has 2 media families but only 1 are provided. All members must be provided.

Поэтому я должен указать оба семейства носителей:

SELECT
    COUNT (*)
FROM
    fn_dump_dblog (
        NULL, NULL, N'DISK', 1, N'D:\SQLskills\FNDBLogTest_Log3_1.bak',
        N'D:\SQLskills\FNDBLogTest_Log3_2.bak', DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT);
GO

Итог

Вот и всё — несколько мощных инструментов, которые можно добавить в ваш арсенал восстановления после сбоев.




28.11.25

Как работали бы индексы на читаемых вторичных репликах групп доступности (AG)?

Автор: Paul Randal, How would indexes on AG readable secondaries work?

В рассылке MVP появилось предложение ввести временные некластерные индексы на читаемых вторичных репликах AG — по аналогии с временной статистикой. Я ответил, что, на мой взгляд, реализовать это чрезвычайно трудно, и пообещал объяснить почему. Ниже — моя аргументация. Замечу: это не исчерпывающий перечень, а лишь основные проблемы, которые я вижу.

27.11.25

Незавершённые контрольные точки и восстановление

Автор: Paul Randal, Incomplete checkpoints and recovery

Ещё в 2009 году я писал о том, как работают контрольные точки (см. How do checkpoints work and what gets logged), и недавно получил по почте вопрос, который, как мне показалось, стоит оформить в короткую статью.

Вопрос (пересказ): Что произойдёт, если контрольная точка начнётся, но не успеет завершиться до сбоя? Будет ли она использована при восстановлении после сбоя?

26.11.25

Важное изменение алгоритма создания VLF в SQL Server 2014

Автор: Paul Randal, Important change to VLF creation algorithm in SQL Server 2014

После выхода SQL Server 2014 ходили разговоры об изменениях в количестве VLF, создаваемых при увеличении или автоувеличении журнала (далее буду говорить «автоувеличение», так как это самый распространённый сценарий). Я немного поэкспериментировал и решил, что разгадал изменение алгоритма. Оказалось, нет. В рассылке MVP вопрос вспыхнул с новой силой, и мы коллективно пришли к выводу, что алгоритм ведёт себя недетерминированно… иначе говоря, мы не понимали, что он делает. Я написал друзьям в CSS, которые изучили код (спасибо, Bob Ward и Suresh Kandoth!) и объяснили изменение.

Изменение весьма существенное: оно нацелено на то, чтобы многочисленные автоувеличения не создавали гигантские количества VLF. Это здорово, потому что слишком много VLF (зависит от размера журнала, но многие тысячи — это слишком много) способны вызвать целый ворох проблем с производительностью при резервном копировании, восстановлении, очистке журнала, репликации, восстановлении после сбоя, откатах и даже при обычных операциях DML.

25.11.25

Когда используется быстрое восстановление?

Автор: Paul Randal, When is fast recovery used?

Разберёмся с вопросом, возникшем в рассылке MCM. Речь шла о быстром восстановлении (подробно я объяснял его в заметке «Логирование блокировок и быстрое восстановление»), а если кратко — это возможность редакции Enterprise предоставить доступ к базе данных после завершения фазы REDO (повторное применение зафиксированных транзакций) восстановления после сбоя и до завершения фазы UNDO (отмена незавершённых транзакций) восстановления после сбоя. Идея в том, что UNDO может занимать намного больше времени, чем REDO, поэтому ранний доступ к базе — благо; именно поэтому это возможность редакции Enterprise (начиная с SQL Server 2005).

Суть вопроса: когда используется быстрое восстановление?

24.11.25

Удаляются ли смешанные страницы при перестроении индекса?

Автор: Paul Randal, Are mixed pages removed by an index rebuild?

Это вопрос, который всплыл на нашем курсе IE1, и я решил оформить ответ в виде статьи в блоге, потому что в нём есть пара тонкостей.

Первые 8 страниц, выделяемые для единицы распределения, — это смешанные страницы из смешанных экстентов, если не включён флаг трассировки 1118.

23.11.25

Новое в SQL Server 2022: снимки баз и интеграция с S3

Автор: Chetna Bhalla, SQL Server 2022: Transforming Storage with Snapshots and S3 Integration

В SQL Server 2022 появились снимки на уровне хранилища для почти мгновенного восстановления и встроенную поддержку совместимых с S3 хранилищ объектов для масштабируемых и экономичных резервных копий и запросов к внешним данным.

Microsoft SQL Server уже давно является одним из лидеров корпоративного управления данными, обеспечивая работу критически важных приложений в самых разных отраслях. С выпуском SQL Server 2022 компания Microsoft сделала смелый шаг к модернизации взаимодействия баз данных с подсистемами хранения. Новшества сосредоточены на мгновенном восстановлении с помощью снимков и на нативной интеграции с хранилищами объектов, совместимыми с S3, — обе возможности призваны удовлетворить растущие потребности гибридных облачных сред, аналитики по большим данным и систем высокой доступности.

В этой статье подробно рассматриваются эти инновации — не только то, что они делают, но и почему это важно для администраторов баз данных, разработчиков и организаций, работающих в современном мире, где всем управляют данные.

22.11.25

Как вычисляются идентификаторы единиц распределения?

Автор: Paul Randal, Inside the Storage Engine: How are allocation unit IDs calculated?

Давненько я не писал о чистой «внутренней кухне», но меня время от времени спрашивают, как вычисляется идентификатор единицы распределения по полям m_objId и m_indexId, которые хранятся в заголовке каждой страницы.

Когда DBCC PAGE выводит содержимое заголовка страницы, она выполняет необходимые вычисления и обращения к метаданным, чтобы показать идентификатор единицы распределения, идентификатор секции (partition), идентификатор табличного объекта и идентификатор индекса.

21.11.25

Идентификатор родительской транзакции в выводе fn_dblog

Автор: Paul Randal, Parent transaction ID in 2012 fn_dblog output

В SQL Server 2012 в вывод различных динамических представлений управления (DMV), функций и команд добавили множество небольших, но полезных сведений.

Одно из новшеств, которое я обнаружил и которому очень рад (да, мне бы почаще выбираться из пещеры :-), — это появление в выводе fn_dblog идентификатора родительской транзакции. Благодаря этому можно видеть, какая транзакция является родительской для вложенных системных транзакций и других подтранзакций.

Зачем это вообще нужно? Мы можем увидеть иерархию и точный порядок транзакций во время выполняемых нами операций с SQL Server, чтобы понимать, как всё устроено «под капотом», без догадок и предположений.

20.11.25

Новое в SQL Server 2025 - Завораживающие возможности RegEx – множественные фильтры

Автор: Louis Davidson, Awesome Use of RegEx in SQL Server – Multiple Filters

Поскольку на этой неделе проходят Microsoft Ignite и PASS Summit, я решил, что стоит написать быстрый пост о RegEx. Буду удивлён, если SQL Server 2025 не выйдет на этой неделе, а с этим релизом появится функция, которую я жду больше всего — RegEx в SQL Server.

Одно из практических применений RegEx — это более мощная фильтрация. Один из проектов, над которыми я работаю (очень медленно) — это размещение некоторых SQL-утилит на GitHub. Утилиты для просмотра метаданных таблицы, поиска столбцов, размеров баз данных и так далее. Обычно я использую LIKE для фильтрации данных, что позволяет мне просто использовать поиск по равенству, или я также могу выполнять поиск по частичному значению, когда не знаю точно, что ищу.

19.11.25

Новое в SQL Server 2025: Always On, AG и FCI

Автор: David Levy, Announcing General Availability of the mssql-python Driver

Дата релиза SQL Server 2025: 18 ноября 2025 г.

В этой статье собран подробный обзор нововведений Always On в SQL Server 2025: быстрый фейловер при устойчивых проблемах, ускорение синхронизации при переключениях, улучшения отказоустойчивости после кратковременной потери кворума, усиление безопасности соединений (TLS 1.3 и TDS 8.0), гибкость управления прослушивателями и маршрутизацией трафика, а также поддержка полноценных резервных копий на вторичных репликах. Материал ориентирован на проектирование, внедрение и эксплуатацию HA/DR решений. Подготовлено с помощью GPT5.

18.11.25

Ошибка SQL Server 1813 при присоединении базы данных: причины и способы устранения

Автор: Andrew Jackson, SQL Server Error 1813 Attach Database: Understanding Causes and Fixes

Столкнуться с ошибкой при работе с базой данных SQL Server для администратора БД — всё равно что кошмар наяву. Одна из таких ошибок — SQL Server error 1813 при присоединении базы данных: она напрямую затрагивает саму базу, не давая пользователям получить доступ к ней и к хранимым данным. В этом техническом материале мы подробно разберём эту ошибку, её причины и решения, которые помогут её устранить.

Где хранятся настройки sp_configure? Ещё одна причина делать резервные копии master…

Автор: Paul Randal, Where are sp_configure settings stored? Another reason to backup master…How are per-column modification counts tracked?

Как-то я опубликовал заметку в нашем блоге журнала "SQL Server Pro" о ложных срабатываниях проверки на повреждения, которые вы гарантированно увидите, если восстановите резервную копию базы master как пользовательскую базу и запустите DBCC CHECKDB на её копии. Это может быть частью переноса проверок целостности на другой сервер или валидации того, что ваши бэкапы корректно восстанавливаются и содержат неповреждённую базу. Впервые увидев такие ложные срабатывания, вы наверняка испугаетесь и решите, что ваш настоящий master повреждён!

Накопительный пакет обновления 22 для SQL Server 2022 - KB5068450

Описание: KB5068450

Скачать: SQLServer2022-KB5068450-x64.exe

SQL Server 2022 — Версия: 16.0.4225.2

Analysis Services — Версия: 16.0.43.252

Дата выпуска: 13 ноября 2025г.

17.11.25

Как отслеживаются изменения по колонкам таблиц?

Автор: Paul Randal, How are per-column modification counts tracked?

Сегодня в рассылке MVP задали вопрос о том, как SQL Server ведёт учёт изменений по каждому столбцу таблицы.

Начиная с версии 2008, скрытая системная таблица sys.sysrscols отслеживает изменения столбцов таблицы с помощью столбца rcmodified. Скрытые системные таблицы (появившиеся в 2005 году, когда мы полностью переписали систему управления метаданными) доступны только при подключении через соединение администратора (DAC), о чём я уже много раз писал. Это означает подключение с помощью SQLCMD -A или префикса admin: в строке подключения.

Эти данные также доступны во представлении каталога sys.system_internals_partition_columns, для которого DAC не требуется. (Я об этом подзабыл — спасибо моему другу Remus Rusanu за напоминание!)

Имейте в виду: всё ниже — выведенное поведение, основанное на моих знаниях и наблюдениях, и в будущих версиях оно может полностью измениться. Всё это не документировано, поэтому не стоит строить на этом программные решения. Если я этого не скажу, мой хороший друг Conor Cunningham при встрече меня отшлёпает :-)

16.11.25

Как работает DBCC CHECKDB WITH ESTIMATEONLY?

Автор: Paul Randal, How does DBCC CHECKDB WITH ESTIMATEONLY work?

Одним из крупнейших потребителей места в tempdb может быть DBCC CHECKDB. Эта команда генерирует всевозможные сведения о том, что она видит в базе данных (они называются фактами), и складывает их в большую рабочую таблицу. Фактами могут быть, к примеру, сообщения вроде «мы прочитали страницу F» или «запись X на странице Y указывает на выведённый за пределы строки столбец LOB в записи A на странице B», или даже целая битовая карта IAM‑страницы. Обычно объём памяти, требуемый для рабочей таблицы, превышает доступный объём, поэтому рабочая таблица проливается в tempdb.

DBCC CHECKDB вынуждена использовать такой механизм генерации фактов, потому что она читает страницы файлов данных не в логическом порядке и не в глубину, а в порядке распределения (allocation order), что быстрее всего. Более того, создаются несколько потоков, и каждый из них читает свой набор страниц, отчего во время работы I/O‑подсистема загружается по максимуму — специальный readahead выполняет упреждающее чтение, выжимая из диска всё, что можно. По мере того как каждый поток генерирует факты, он передаёт их процессору запросов, который сортирует их по ключу, заданному DBCC CHECKDB (идентификаторы страницы, объекта, индекса и т. п.), и вставляет в рабочую таблицу.

15.11.25

Начальные номера последовательностей VLF и размер файла журнала по умолчанию

Автор: Paul Randal, Initial VLF sequence numbers and default log file size

Мы проводим двухнедельное корпоративное обучение у финансового клиента в Нью‑Йорке, и на сегодняшней сессии по архитектуре журнала транзакций меня спросили, почему номера последовательностей VLF (virtual log file) в новой базе не начинаются с единицы.

14.11.25

Правда ли, что изменения ключей индекса выполняются «по месту»?

Автор: Paul Randal, Do changes to index keys really do in-place updates?

Сегодня утром в Twitter развернулась интересная дискуссия (её начал мой хороший друг Erin Stellato) о «встроенных» обновлениях (in‑place updates) записей индекса, когда значение ключа меняется, но запись остаётся на той же странице. Разные источники, включая книгу SQL Server 2008 Internals (стр. 361 — этот фрагмент я не писал и не рецензировал :-) ), описывают процесс — увы, неверно. Там говорится, что запись останется ровно в той же позиции на странице и изменятся лишь байты, хранящие ключ.

Это не так. Настоящие in‑place‑обновления значений ключей индекса не выполняются, начиная с версии 2005. Давайте нырнём в кроличью нору…

13.11.25

Фрагментация кучи лечится созданием и удалением кластерного индекса - миф!

Автор: Paul Randal, A SQL Server DBA myth a day: (29/30) fixing heap fragmentation

Миф №29: исправить фрагментацию кучи можно, создав и затем удалив кластерный индекс.

Неееееет!!!

Это одно из худших действий, которые только можно совершить, если не считать сжатия базы данных.

12.11.25

Три мифа о коэффициенте заполнения (fill factor)

Автор: Paul Randal, A SQL Server DBA myth a day: (25/30) fill factor

Это короткая статья о мифах вокруг коэффициента заполнения (fill factor) — тему, которую я настойчиво прояснял ещё в Books Online для SQL Server 2005.

Миф №25: разные заблуждения о коэффициенте заполнения.

Все ложные