Одним из крупнейших потребителей места в tempdb может быть DBCC CHECKDB. Эта команда генерирует всевозможные сведения о том, что она видит в базе данных (они называются фактами), и складывает их в большую рабочую таблицу. Фактами могут быть, к примеру, сообщения вроде «мы прочитали страницу F» или «запись X на странице Y указывает на выведённый за пределы строки столбец LOB в записи A на странице B», или даже целая битовая карта IAM‑страницы. Обычно объём памяти, требуемый для рабочей таблицы, превышает доступный объём, поэтому рабочая таблица проливается в tempdb.
DBCC CHECKDB вынуждена использовать такой механизм генерации фактов, потому что она читает страницы файлов данных не в логическом порядке и не в глубину, а в порядке распределения (allocation order), что быстрее всего. Более того, создаются несколько потоков, и каждый из них читает свой набор страниц, отчего во время работы I/O‑подсистема загружается по максимуму — специальный readahead выполняет упреждающее чтение, выжимая из диска всё, что можно. По мере того как каждый поток генерирует факты, он передаёт их процессору запросов, который сортирует их по ключу, заданному DBCC CHECKDB (идентификаторы страницы, объекта, индекса и т. п.), и вставляет в рабочую таблицу.
Когда генерация фактов завершена, процессор запросов возвращает их обратно DBCC CHECKDB, чтобы та могла сопоставить их между собой (например: страница X ссылается на страницу Y — значит, мы обязаны были видеть страницу Y). Этот этап называется агрегацией. Если обнаруживаются несовпадающие или лишние факты, это признак повреждения, и формируется соответствующая ошибка.
Вот схема процесса:
Поскольку DBCC CHECKDB способна потреблять очень много пространства в tempdb, мы добавили возможность попросить её оценить требуемый объём — опция WITH ESTIMATEONLY. Вывод выглядит примерно так:
Estimated TEMPDB space needed for CHECKALLOC (KB)
————————————————-
56
(1 row(s) affected)
Estimated TEMPDB space needed for CHECKTABLES (KB)
————————————————–
3345
(1 row(s) affected)
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Это не общий объём, нужный для проверки всей базы, потому что DBCC CHECKDB никогда не проверяет её целиком за один проход (если только не использовать новый трассировочный флаг 2562). Чтобы ограничить требуемое место в tempdb, база разбивается на пакеты (batches). Пакет формируется путём добавления всё новых таблиц, пока не будет достигнут один из пределов:
- в пакете 512 индексов или больше;
- суммарная оценка объёма фактов для пакета превышает 32 МБ.
Минимально возможный пакет — одна таблица и все её индексы; поэтому очень большая таблица легко переступит порог в 32 МБ фактов (теоретически — и предел в 512 индексов).
Оценка размера фактов выполняется путём прохода по всем разделам (partitions) всех индексов таблицы (помните, что с точки зрения SQL Server неразделённая таблица или индекс — это частный случай одного раздела) и суммирования:
- удвоенной суммы всех страниц, выделенных разделу (HoBt, LOB и SLOB);
- утроенного числа страниц HoBt в кластерном индексе;
- удвоенного числа столбцов LOB в таблице;
- удвоенного числа строк таблицы — если это куча;
- произведения максимального размера строки на число страниц HoBt.
Эти суммы умножаются на размеры соответствующих фактов.
Опция WITH ESTIMATEONLY проходит по всем пакетам и выводит наибольшую из оценок суммарного объёма фактов по всем пакетам. Это заведомо консервативная оценка, однако в некоторых патологических случаях она может дать сбой, потому что не способна учесть абсолютно все возможные схемы.
Ещё один кусочек знаний, который можно смело выгрузить из головы! :-)
PS Будьте внимательны: мне известно о множестве случаев ошибки в SQL Server 2008 R2 и 2012, когда вывод опции оказывается неправдоподобно низким. Команда разработки знает о проблеме и работает над ней. В 2014 всё снова работает (я также слышал, что исправлено в 2012 SP2, но косвенные свидетельства говорят, что нет).


Комментариев нет:
Отправить комментарий