Выбрать главу

В строке Average data length: 0.00, total dup: 73372, max dup: 32351 число max dup указывает длину самой длинной цепочки дубликатов, подсчитанной почти для половины узлов. Число total dup говорит, что каждый узел, за исключением одного, является дубликатом.

Это самый классический случай, когда проектировщик применяет внешний ключ без рассмотрения его распределения. Вероятно, это столбец стиля BOOLEAN или таблица соответствия (lookup) либо с очень небольшим количеством значений, либо практически с одним значением.

Примером этому было приложение формирования списка избирателей, которое сохраняло столбец страны проживания. Избирателей было приблизительно 3 миллиона, а регистрация была принудительной. База данных имела таблицу COUNTRY, содержащую более 300 стран, снабженную ключами в кодах стран CCCIT. Она присутствовала чуть ли не в каждой таблице базы данных в качестве внешнего ключа. Беда была в том, что почти все избиратели жили в одной стране.

Средняя длина данных (Average data length) - это средняя длина хранимого ключа. Здесь мало что можно сделать с объявленной длиной. Нулевое значение средней длины означает лишь то, что в процессе сжатия не осталось "пищи" для вычисления среднего значения.

Строка Fill distribution показывает, что все 109 страниц находятся в диапазоне 80-99 процентов, что является хорошим заполнением. Распределение заполнения является долей пространства каждой страницы, используемой для данных и указателей. От восьмидесяти до девяноста процентов - это хорошо. Меньшее распределение заполнения является весьма серьезным напоминанием, что вы должны пересоздать индекс.

Анализ 2

Следующий пример показывает статистику сгенерированного системой индекса для первичного ключа в той же таблице:

Index RDB$PRIMARY10 (0)

Depth: 3, leaf buckets: 298, nodes: 73373

Average data length: 10.00, total dup: 0, max dup: 0

Fill distribution:

0 - 19% = 1

80 - 99% = 297

Длина ключа 10 означает, что выполнено некоторое сжатие. Это нормально и хорошо. То что одна строка мало заполнена- вполне нормально: количество узлов не соответствует точно страницам.

Анализ 3

Эта база данных имеет маленькую таблицу, хранящую временные данные для проверки достоверности. Она периодически очищается и наполняется снова. Следующая статистика генерируется для внешнего ключа этой таблицы:

Index RDB$FOREIGN263 (1)

Depth: 1, leaf buckets: 10, nodes: 481

Average data length: 0.00, total dup: 480, max dup: 480

Fill distribution:

0 - 19% = 10

Total dup и max dup идентичны - каждая строка имеет одинаковое значение в ключе индекса. Селективность не может быть хуже этой. Уровень заполнения, очень низкий для всех страниц, наводит на мысль о разнородных удалениях. Если бы это не было маленькой таблицей, такой индекс был бы ужасен.

Данная таблица - очередь обработки - очень динамична, она хранит до 1000 новых строк в день. После проверки данных строки переносятся в порождающие таблицы, а строки разрабатываемой таблицы удаляются, приводя к замедлению работы системы. Частое резервное копирование и восстановление базы данных необходимо, чтобы дела шли нормально.

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

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

* Если возможно, удаляйте все строки за один раз, а не выполняйте их удаление одну за другой в случайном порядке. Удалите ограничение внешнего ключа, удалите строки и подтвердите транзакцию. Заново создайте ограничение. Поскольку это не длинная транзакция, задерживающая сборку мусора, новый индекс будет полностью пустым.

* Если удаления должны быть последовательными, выберите время, чтобы получить исключительный доступ и использовать ALTER INDEX для пересоздания индекса. Это будет более быстро и предсказуемо, чем инкрементная сборка мусора в огромной цепочке дубликатов.

Другие переключатели gstat

Статистика утилиты gstat может предоставить полезную информацию о других действиях с базой данных.

Переключатель -header

Эта строка

gstat -header база-данных

отображает суммарную информацию заголовочной страницы базы данных. На рис. 18.5 показан пример.

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

Рис. 18.5. Пример вывода заголовочной страницы утилитой gstat

Таблица 18.3. Вывод gstat -h[eader]

Элемент

Описание

Flags

Флаги

Checksum

Контрольная сумма заголовочной страницы. В прототипе (InterBase) это было уникальное значение, вычислявшееся по всем данным заголовочной страницы. В Firebird это всегда 12 345. Когда заголовочная страница сохраняется на диске, а затем считывается, контрольная сумма найденной страницы сравнивается с 12 345, и если они не соответствуют, то вызывается ошибка контрольной суммы. Это перехватывает некоторые виды физического разрушения

Generation

Каждый раз увеличивается на единицу, когда заголовочная страница записывается на диск

Page size

Текущий размер страницы базы данных в байтах

ODS version

Версия структуры на диске (ODS) для базы данных. Это будет 10 для версии 1,0.x и 10.1 для версии 1.5

Oldest transaction

Идентификатор самой старой "заинтересованной" транзакции. Информацию об этом см. в главе 25

Oldest active

Идентификатор самой старой активной транзакции

Oldest snapshot

Идентификатор самой старой транзакции, которая не является в настоящий момент подходящей для сборки мусора (т. е. эта и другие, более поздние транзакции не являются для этого подходящими)

Next transaction

Идентификатор, который Firebird назначит следующей транзакции. Разница между самой старой активной транзакцией и следующей транзакцией определяет, когда начнется чистка базы данных[61]. Значение по умолчанию 20 000. См. разд. "Гигиена базы данных" главы 15

Bumped transaction

Теперь устарело

Sequence number

Последовательный номер заголовочной страницы. Всегда ноль

Next connection ID

Номер идентификатора следующего соединения с базой данных

Implementation ID

Архитектура аппаратуры, на которой была создана база данных

Shadow count

Количество наборов оперативных копий для базы данных

Number of cache buffers

Размер в страницах кэша базы данных. Ноль означает, что база данных использует значение по умолчанию сервера

(DefaultDbCachePages в firebird.config, default_cache_pages в ibconfig/isc_config для версии 1.0.x)

Next header page

вернуться

61

Это неверно, и автор подтвердил ошибку. Next transaction не имеет никакой связи со sweep. Автоматический sweep стартует, когда разница между Oldest Snapshot и Oldest Interesting больше Sweep interval (в Firebird 2.0 за верхнюю границу берется не Oldest Snapshot, a Oldest Active). -Прим. науч. ред.