Это обновлённая версия статьи из моего прежнего блога о механизме хранения; теперь она также охватывает страницы карт DIFF и ML.
В предыдущих статьях этой серии я разобрал основы хранения в файлах базы данных:
- Анатомия страницы/Анатомия записи
- Анатомия экстента
- Страницы IAM, цепочки IAM и единицы распределения (allocation units)
Последние элементы в «головоломке» распределения — это прочие страницы-карты учёта распределения: страницы GAM, SGAM, PFS, ML map и DIFF map. Всё, что описано ниже, справедливо для версий на сегодня. Для любой из этих страниц можно выполнить дамп DBCC PAGE в режиме «dump style 3»: утилита интерпретирует страницу и представит данные учёта распределения в удобочитаемом виде.
Страницы GAM
GAM — это Global Allocation Map (глобальная карта распределения). Напомню: файлы данных базы разделяются на интервалы GAM (не физически, а концептуально). Интервал GAM соответствует объёму пространства, который отслеживают битовые карты на страницах GAM, SGAM, ML map, DIFF map и IAM, — это 64000 экстентов, или почти 4GB. Эти битовые карты имеют одинаковый размер у всех пяти типов страниц и содержат по одному биту на экстент, но смыслы этих битов различаются в зависимости от типа страницы-карты.
Семантика битов в карте GAM такова:
- bit = 1: экстент доступен для распределения (можно считать, что он «закреплён» за страницей GAM)
- bit = 0: экстент уже выделен для использования
Эти смыслы одинаковы и для смешанных (mixed), и для выделенных/однородных (uniform/dedicated) экстентов.
Важно: в начале каждого интервала GAM находится экстент GAM, содержащий глобальные страницы распределения, которые отслеживают данный интервал. Этот экстент GAM нельзя использовать для обычных размещений страниц. Первый экстент GAM начинается со страницы 0 в файле и имеет следующую разметку:
- Страница 0: страница заголовка файла (об этом — в другой статье)
- Страница 1: первая страница PFS
- Страница 2: первая страница GAM
- Страница 3: первая страница SGAM
- Страница 4: не используется в 2005+
- Страница 5: не используется в 2005+
- Страница 6: первая страница DIFF map
- Страница 7: первая страница ML map
Страницы SGAM
Помню, как в прошлом году по почте обсуждали, что означает буква «S» в SGAM. За годы существования встречались разные расшифровки, и внутри, и за пределами Microsoft, но официальное название в Books Online — Shared Global Allocation Map (разделяемая глобальная карта распределения). Честно говоря, мы почти всегда произносим их просто «эс-гам» и не расшифровываем.
Как сказано выше, битовая карта SGAM по структуре и покрываемому интервалу точно такая же, как у GAM, но семантика битов иная:
- bit = 1: экстент — смешанный и, вероятно, имеет хотя бы одну нераспределённую страницу, доступную для использования (используется оптимистичный алгоритм обновления)
- bit = 0: экстент либо выделенный, либо смешанный, но без свободных страниц (для целей SGAM это практически одно и то же: SGAM служит для поиска смешанных экстентов со свободными страницами)
Комбинация страниц GAM, SGAM и IAM
Если рассматривать вместе страницы GAM, SGAM и IAM (напомню: в битовой карте IAM бит установлен, если экстент закреплён за цепочкой IAM/единицей распределения), то допустимы следующие комбинации битов:
GAM | SGAM | Любая IAM | Комментарий |
---|---|---|---|
0 | 0 | 0 | Смешанный экстент, все страницы распределены |
0 | 0 | 1 | Выделенный экстент (должен быть закреплён только за одной страницей IAM) |
0 | 1 | 0 | Смешанный экстент с >= 1 свободной страницей |
0 | 1 | 1 | Недопустимое состояние |
1 | 0 | 0 | Нераспределённый экстент |
1 | 0 | 1 | Недопустимое состояние |
1 | 1 | 0 | Недопустимое состояние |
1 | 1 | 1 | Недопустимое состояние |
Как видно, для конкретного экстента допустимы лишь 4 из 8 возможных комбинаций битов. Любое иное указывает на некоторую форму повреждения и может привести к самым неприятным последствиям.
Страницы ML map
ML — это Minimally Logged (минимально журналируемые). Эти страницы отмечают экстенты, которые были изменены минимально журналируемыми операциями со времени последнего резервного копирования журнала транзакций при использовании модели восстановления BULK_LOGGED. Идея такова: следующее резервное копирование журнала сохранит журнал как обычно, а затем включит все экстенты, отмеченные как изменённые в этих битовых картах. Комбинация этих экстентов и журнала в резервной копии даёт «дельту» изменений, произошедших в базе после предыдущего бэкапа журнала. После чтения битовые карты страниц ML очищаются. Если вы никогда не используете модель BULK_LOGGED, эти страницы не задействуются.
Битовая карта ML имеет ту же структуру и тот же охват, что и у GAM, но семантика битов иная:
- bit = 1: экстент был изменён минимально журналируемой операцией после последнего бэкапа журнала
- bit = 0: экстент не изменялся
Страницы DIFF map
DIFF — это «дифференциальные» страницы. Они отмечают экстенты, изменённые со времени последнего полного резервного копирования. Распространённое заблуждение — будто эти битовые карты отражают изменения со времени последнего дифференциального бэкапа. На деле в дифференциальную копию попадают все экстенты, изменившиеся со времени последнего полного бэкапа. Время восстановления можно существенно сократить, применяя дифференциальные копии, — тогда не нужно восстанавливать все бэкапы журналов за период между полным и последним дифференциальным бэкапами (об этом подробнее — в отдельной статье). Битовые карты не очищаются до следующего полного бэкапа. Заметьте: речь не обязательно о полном бэкапе базы данных. И полные, и дифференциальные бэкапы могут выполняться на уровне базы, группы файлов или отдельного файла.
Битовая карта DIFF по структуре и охвату идентична карте GAM, но смыслы битов иные:
- bit = 1: экстент изменён со времени последнего полного бэкапа
- bit = 0: экстент не изменялся
Страницы PFS
PFS — это Page Free Space (свободное место на странице), но фактически PFS отслеживает больше параметров. Помимо интервалов GAM, каждый файл базы также (концептуально) делится на интервалы PFS. Интервал PFS — это 8088 страниц, то есть около 64MB. Страница PFS — это не битовая карта, а «байтовая»: по одному байту на каждую страницу в интервале PFS (кроме самой страницы PFS).
Биты в каждом таком байте кодируют следующее:
- биты 0–2: сколько свободного места на странице
0x00
— пусто0x01
— заполнено от 1 до 50%0x02
— 51–80%0x03
— 81–95%0x04
— 96–100%
- бит 3 (
0x08
): есть ли на странице одна или несколько фантомных (ghost) записей? - бит 4 (
0x10
): является ли страница страницей IAM? - бит 5 (
0x20
): является ли страница «смешанной»? - бит 6 (
0x40
): страница распределена? - бит 7 — не используется
Например, страница IAM будет иметь значение байта PFS 0x70
(распределена + IAM + mixed).
Свободное место отслеживается только для страниц, хранящих LOB‑значения (то есть text/image, (n)varchar(max), varbinary(max), XML и «row-overflow»), и для страниц кучи (heap). Это потому, что только на этих страницах данные не упорядочены и вставки могут происходить куда угодно, где есть место. В индексах существует явный порядок, поэтому точка вставки не выбирается произвольно.
Момент, когда байт PFS «сбрасывается», неочевиден. Байт PFS полностью сбрасывается лишь при повторном распределении страницы. При освобождении страницы меняется только бит «статуса распределения» — это облегчает откат операции освобождения.
Ниже — пример. В базе есть простая таблица с одной строкой. Дамп DBCC PAGE для страницы IAM показывает:
PFS (1:1) = 0x70 IAM_PG MIXED_EXT ALLOCATED 0_PCT_FULL
Если удалить таблицу в явной транзакции, а затем снова выполнить DBCC PAGE, вывод включает:
PFS (1:1) = 0x30 IAM_PG MIXED_EXT 0_PCT_FULL
А если откатить транзакцию, вывод DBCC PAGE возвращается к виду:
PFS (1:1) = 0x70 IAM_PG MIXED_EXT ALLOCATED 0_PCT_FULL
Комментариев нет:
Отправить комментарий