2. Индексация
Наложение иерархии предполагает, что имеется возможность эффективной выборки записей в последовательности иерархического обхода. В данной работе предлагается задачу быстрого поиска записей решать с помощью индексов, а задачу быстрого чтения записей с помощью кластерных индексов.
Индекс в общем случае представляет собой структуру, каждый элемент которой состоит из двух полей: ключа индекса и указателя на запись индексируемой таблицы (рис. 3). Ключ индекса содержит упорядоченные значения некоторого атрибута таблицы, а указатель определяет запись таблицы, имеющую такое же значение атрибута. При этом сами записи хранятся неупорядоченно. Индекс на первичном ключе обычно называют первичным индексом.
Рис. 3. Индекс
Индекс по нескольким атрибутам таблицы называется составным. Индекс на комбинации атрибутов F1, F2 … Fn (в указанном порядке) может также использоваться в качестве таких индексов: только на одном атрибуте F1, на комбинации атрибутов F1, F2, на комбинации атрибутов F1, F2, F3 и т.д. Для индексации атрибута F2 потребуется создание дополнительного индекса.
Для повышения скорости доступа к данным используют кластеризацию. Основная идея кластеризации заключает в том, что необходимо обеспечить хранение логически связанных записей в непосредственной близости друг от друга. Различают внутритабличную кластеризацию, т.е. кластеризацию, применяемую в пределах одной таблицы, и межтабличную кластеризацию, т.е. кластеризацию, применяемую больше чем к одной таблице.
При использовании кластеризации записи хранятся в кластерном индексе, записи упорядочены по значениям кластерного ключа. Некластерный (обычный) индекс в этом случае содержит вместо указателя на запись значение кластерного ключа (рис. 4) Если кластерный индекс не уникален, то к индексируемым значениям добавляется суррогатная (т.е. генерируемая системой) «добавка», которая делает их уникальными. Эта добавка скрыта от пользователя.
Рис. 4. Кластерный индекс
В предложенной модели экземпляры объектов должны быть логически упорядочены по значениям позиционного первичного ключа, поэтому имеет смысл хранить их в такой же последовательности. Для этого создается кластерный индекс по позиционному ключу – коду экземпляра.
Рассмотрим, как осуществляется наложение иерархии в предложенной модели данных. Допустим, имеется следующая иерархическая структура, выраженная языком XML:
<Base>
<Tab1 D="d1"> <!-- A: position()=1 -->
<Tab2 E="e1" F="f1"> <!-- B: position()=1 -->
<Tab3 G="g1"/> <!-- C: position()=1 -->
</Tab2>
<Tab2 E="e2" F="f1"> <!-- B: position()=2 -->
<Tab3 G="g2"/> <!-- C: position()=1 -->
<Tab3 G="g1"/> <!-- C: position()=2 -->
</Tab2>
</Tab1>
<Tab1 D="d2"> <!-- A: position()=2 -->
<Tab2 E="e3" F="f1"> <!-- B: position()=1 -->
<Tab3 G="g4"/> <!-- C: position()=1 -->
<Tab3 G="g3"/> <!-- C: position()=2 -->
</Tab2>
</Tab1>
</Base>
Необходимо представить эту структуру в реляционной модели. Для этого предлагается вариант, показанный рис. 5.
Рис. 5. Наложение иерархии
Здесь для кодирования позиций вместо десятичных цифр предлагается использовать латинские буквы. Использование букв вместо цифр связано с тем, что с помощью одного цифрового символа можно закодировать только 10 записей, а с помощью буквенного символа – 52.
Корневая таблица имеет простой первичный ключ, а каждая дочерняя таблица – составной первичный ключ. Внешние ключи входят в состав первичного ключа и ссылаются на первичные ключи всех таблиц-предков данной таблицы. Составной позиционный первичный ключ определяет уникальность записи в пределах любой записи-предка. Поэтому, несмотря на избыточность, предлагается именно такой вариант наложения иерархии.
Для выбранного варианта наложения иерархии индексация показана на рис. 6.
Рис. 6. Индексация
Здесь созданы кластерные индексы для первичных ключей таблиц. Поскольку первичные ключи составные, кластерные индексы также будут составными. В индексации внешних ключей нет необходимости, так как они входят в состав ключа кластерного индекса и находятся в его начале. Напротив, дополнительно проиндексирован атрибут С#, поскольку составной индекс А#B#C# ничего не дает для поиска по значениям C# – они находятся не в начале ключа индекса, а в его конце. Также создан индекс для неключевого атрибута E таблицы 2.
Идею составных кластерных индексов в данной работе предлагается естественным образом распространить на ключи таблиц. То есть, вместо составного позиционного ключа из нескольких атрибутов, предлагается использовать простой (из одного атрибута) позиционный ключ, который является ключом кластерного индекса. В этом случае отпадает необходимость дополнительно индексировать атрибут С#, так как он войдёт в состав простого ключа.
Таким образом, код экземпляра, который на уровне предлагаемой модели является простым иерархическим позиционным первичным ключом, на уровне хранения является ключом составного кластерного индекса.
В этом варианте индексации использовалась внутритабличная кластеризация. Межтабличная кластеризация показана на рис. 7.
Рис. 7. Межтабличная кластеризация
Здесь показан кластерный индекс для первичных ключей, принадлежащих разным таблицам. Это позволяет физически хранить записи разных таблиц в связанном виде в последовательности иерархического обхода. При этом имя таблицы необходимо включить в состав ключа индекса.
Необходимо также учесть возможную разреженность данных. Пример разреженных данных можно увидеть на рис. 7, в виде обилия незаполненных ячеек. Для разрешения этой ситуации на физическом уровне предлагается хранить записи не как два последовательных списка (один для имен атрибутов в описаниях, другой для значений в данных), а как один упорядоченный список пар имя атрибута – значение, не храня в списке пары, в которых отсутствует значение. Таким образом, имя атрибута предлагается включить в состав ключа индекса.
Оба варианта кластерной индексации, соответствующие рис. 6 и рис. 7, в терминах предложенной модели данных представлены на рис. 8.
Рис. 8. Варианты кластерной индексации
Выделение конкретного поддерева на физическом уровне при использовании межтабличных кластерных индексов сводится к быстрому чтению нескольких последовательных блоков памяти. При использовании внутритабличных индексов чтение займет больше времени: присоединение одного поддерева под узел другого сводится к соединению объектов по совпадающим значениям понятий и выделению второго поддерева и т. д.
Несмотря на более медленную скорость сборки дерева, предлагается выбрать первый вариант, поскольку он практически более удобен с точки зрения работы поисковой машины – в XML запросы чаще всего строятся на основе имен узлов, а не их позиций.
Таким образом, для быстрого чтения экземпляров в последовательности иерархического обхода, создаётся кластерный индекс кодов экземпляров, который является основной структурой хранения. В кластерном индексе экземпляры каждого объекта хранятся в порядке кодов экземпляров вместе с данными экземпляров. Для быстрого поиска требуемых экземпляров реализуются некластерные индексы понятий, которые ссылаются на коды экземпляров кластерного индекса (рис. 9).
Рис. 9. Индексации
Структурированное значение понятия в общем случае может состоять из нескольких слов, разделённых пробелами, некластерный индекс создаётся для отдельных слов значений, поэтому в него дополнительно добавляется номер слова в значении понятия.
