Как IB Database создает индексы и управляет ими?

На вопросы отвечает Ann Harrison.
Перевод: Дмитрий Кузьменко.
 

Что происходит при операции CREATE INDEX?

Когда вы создаете новый индекс, появляются новые записи в системных таблицах RDB$INDICES и RDB$INDEX_SEGMENTS. Когда изменения подтверждаютс (commit), IB строит индекс. Большинство системных утилит создает специальные транзакции для обновления метаданных (включая создание индекса), которые подтверждаются (commit) сразу после выполнения соответствующего оператора DDL (Data Definition Language), но время подтверждения зависит от используемого интерфейса. Изменени метаданных порождают "задания", которые ассоциируются с транзакцией и выполняютс по commit.

Когда создание вашего индекса подтверждено (committed), IB читает все записи таблицы в их естественном порядке собирая пары из ключевого значени и идентификатора записи (так называемого db-key). Затем этот набор сортируется по ключевому значению и создается нижняя часть индекса, со сжатием дубликатов ключевых значений. Перед тем как завершится commit, индекс уже построен и прилинкован в список индексов на корневой странице отношений (relations). Для нескольких тысяч записей процесс происходит очень быстро. Если у вас несколько миллионов записей, то это происходит дольше. Вставки и обновления записей в таблице "замрут" (как мне кажется) на время создания индекса.
 
Примечание КД. Оценить скорость создания индексов можно в статье по тестированию скорости вставки.
Версионирование записей IB усложняет задачу, поскольку некоторые записи могут иметь разные значения индексируемых полей. Код, который строит индексы, стартует специальную транзакцию, которая видит все существующие на данный момент версии записей (естественно, committed).
 

Что происходит, когда индекс деактивируется, добавляются несколько записей, и индекс активируется?

Когда вы деактивируете индекс, и транзакция, которая деактивирует его, подтвердится, индекс удаляется из списка в корневой странице и все страницы индекса возвращаются как свободное пространство. Реактивация индекса эквивалентна созданию индекса, за исключением того что запись в RDB$INDICES не создается, а обновляется.
 
Примечание КД. Увы, это не так – alter index inactive существенно медленнее, чем drop index. В этом можно убедиться, прочитав статью по проблемам удаления большого количества записей).


Как я могу быть уверен что индекс соответствует данным?

Как можно быть вообще в чем-то уверенным? Один из фундаментальных принципов создания систем управления данными – синхронизация индексов и данных. Потеря ключей в индексе может быть еще хуже чем потеря данных в таблице. Тестирование индексов – один из самых серьезных тестов при выпуске новой версии РСУБД. Если вы действительно хотите, то можете написать простой тест, который читает таблицу, а затем делает поиск по индексу, чтобы убедиться, что все записи есть в индексе – разумеется, нужно помнить о возможных дубликатах значений в индексе.

Если же вопрос в том, стоит ли периодически деактивировать и активировать индексы, то ответ – нет. Если вы спрашиваете, возможна ли рассинхронизация данных и индекса при этом, ответ – нет. Перестраивание индекса упаковывает ключевые значения плотнее, делая индекс меньше по объему, но это не отражается на содержании индекса.
 
Примечание. Оценить степень упаковки индексов можно в статье "Хранение guid и размер индексов".
 

Как происходит индексирование многих версий записей?

Когда запись обновляется или удаляется, ее старая версия сохраняется с пометкой в виде идентификатора создавшей версию транзакции, и тут же создается новая версия (или stub удаления) с тем же идентификатором транзакции. В зависимости от активности в базе данных, и длительности транзакций, одна запись может иметь несколько версий. Каждая версия может иметь разные значени индексируемых полей. Индекс создается с ключом для КАЖДОЙ версии. Когда старые версии записей уничтожаются, так же уничтожаются и эти ключевые записи в индексе.

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


Производится ли сборка мусора версий ключей в индексе?

Ключ всегда удаляется из индекса, если запись физически удаляется со страницы (со всеми ее версиями). Однако сжатие индекса в IB версий 4.x не производится, и со временем БД растет. Это становится проблемой если индекс построен по полю, значение которого постоянно увеличивается – например, идентификатор, создаваемый при помощи генератора (номер заказа, код клиента и т. п.). Если каждый день создается и удаляется большое количество таких записей, то индекс становится несбалансированным и его глубина увеличивается (более 3). В IB 5.0 сборка мусора для индексов объявлена среди новых возможностей.
 
Примечание. См. статью по определению глубины индекса

Подпишитесь на новости Firebird в России

Подписаться