СУБД с хранением данных по столбцами и по строкам

Планы с доступом только к индексам.


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

Для преодоления этих проблем авторы пытались использовать второй подход, при котором базовые отношения хранятся в обычном строчном виде, но на каждом столбце каждой таблицы определяется дополнительный некластеризованный индекс в виде B-дерева. Планы выполнения запросов с доступом только к индексам (index-only plan), для которых требуется специальная поддержка со стороны СУБД, имеющаяся в System X, выполняются путем построения списков пар (record-id, value), удовлетворяющих предикатам, и слиянием этих списков в основной памяти, если для одной таблицы имеется несколько предикатов. Если для требуемых полей в запросе отсутствуют предикаты, то производятся полные списки пар (record-id, value) для всех значений соответствующих столбцов.

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

Одной из проблем этого подхода является то, что если в запросе отсутствует предикат на некотором столбце, то для выборки требуемых значений требуется последовательное сканирование индекса, которое может выполняться медленнее сканирования неупорядоченного файла (как было бы при применении подхода вертикального разделения).

Оптимизацией подхода является создание индексов с составными ключами, в которых вторичные ключи берутся из столбцов без предикатов. Например, рассмотрим запрос SELECT AVG(salary) FROM emp WHERE age>40. Если имеется составной индекс с ключом (age, salary), то ответ на этот запрос может быть получен прямо через этот индекс. Если же имеются отдельные индексы с ключами (age) и (salary), то план с доступом только к индексам будет вынужден найти все идентификаторы записей, удовлетворяющих условию age>40, а потом слить полученный список с полным списком пар (record-id, salary), построенным по индексу с ключом (salary), что будет выполняться гораздо медленнее.

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


В этих планах доступ ко всем столбцам производится через некластеризованные B-деревья, и столбцы одной и той же таблицы соединяются по идентификаторам записей (переход по указателям к хранимым отношениям никогда не производится). В плане для запроса 2.1 выполняется полное индексное сканирование столбцов suppkey, revenue, partkey и orderdate таблицы фактов, и затем результаты соединяются методом хэш-соединений. В этом случае индексное сканирование обеспечивает относительно быстрый просмотр всего индексного файла, и при этом не требуется подвод дисковых головок при переходе от одной листовой страницы к другой. Однако хэш-соединения выполняются довольно медленно, поскольку приходится комбинировать пары из 60 миллионов экземпляров столбцов, каждый из которых занимает сотни миллионов мегабайт дискового пространства. Заметим, что для этого случая хэш-соединение, по-видимому, является наилучшим методом, поскольку результаты индексного сканирования не упорядочены по идентификаторам записей, и выполнение сортировки списков идентификаторов записей или применение индексных вложенных циклов, вероятно, были бы гораздо медленнее. Как обсуждается ниже, авторам не удалось найти способ принудить System X отложить выполнение этих соединений на более позднюю фазу плана, что позволило бы приблизить эффективность этого подхода к эффективности подхода с вертикальным разделением.

После соединения столбцов таблицы фактов в плане используется индексное сканирование в диапазоне значений ключа для извлечения отфильтрованного столбца part.category, и результат хэш-соединяется со столбцами part.brand1 и part.part-key (доступ к которым производится путем полного индексного сканирования). Затем полученный результат хэш-соединяется с уже соединенными столбцами таблицы фактов. После этого выполняется хэш-соединение столбца supplier.region (отфильтрованного путем индексного сканирования в диапазоне значений ключа) со столбцом supplier.suppkey (доступ к которому производится путем полного индексного сканирования), и результат этого соединения хэш-соединяется с таблицей фактов. Наконец, используется полное индексное сканирование столбцов dwdate.datekey и dwdate.year, они хэш-соединяются, и результат этого соединения хэш-соединяется с таблицей фактов.



Содержание раздела