2008 г.
Базы данных. Вводный курс
Сергей Кузнецов
Назад Содержание Вперёд
12.2.3. Организация внешней памяти в базах данных System R
Как уже говорилось,
база данных System R располагается в одном или нескольких сегментах
внешней памяти. Каждый сегмент состоит из страниц данных и страниц
индексной информации. Размер страницы данных в сегменте может быть
выбран равным либо 4, либо 32 килобайтам; размер страницы индексной
информации равен 512 байтам. Кроме того, при работе RSS
поддерживается дополнительный набор данных для ведения журнала. Для
повышения надежности журнала (а это наиболее критичная информация;
при ее потере восстановление базы данных после сбоев невозможно)
этот набор данных дублируется на двух внешних носителях.
Страницы данных и идентификаторы кортежей
В
каждой странице данных хранятся кортежи одной или нескольких таблиц.
Фундаментальным понятием RSS является идентификатор
кортежа
(tuple identifier – tid). Гарантируется неизменяемость tid'а
во все время существования кортежа в базе данных независимо от
перемещений кортежа внутри страницы и даже при перемещении кортежа в
другую страницу. Потребность в перемещении кортежей возникает по той
причине, что кортеж, занесенный в некоторую таблицу базы данных,
вообще говоря, во время своего существования может увеличиваться в
размерах (если к этой таблице добавляется новое поле, или если в ней
имеется хотя бы одно поле, типом данных которого являются строки
символов переменного размера). Реально tid представляет собой пару
<номер страницы,
индекс описателя кортежа в странице>
.
При этом кортеж может реально располагаться в данной странице (рис.
12.1a)
или в другой странице (рис. 12.1b).
Рис. 12.1. Идентификатор кортежа и расположение кортежа в странице данных
Как
показывает рис. 12.1, в каждой странице данных имеются две области:
область хранения описателей кортежей и область хранения самих
кортежей. Один из остроумных приемов, примененных в System
R,
состоит в том, что обе эти области являются динамическими, т.е. в
странице данных заранее не резервируется место под описатели
кортежей. Легко видеть, что выделение фиксированной части страницы
данных под описатели кортежей (вмещающей, скажем, k
описателей)
потенциально привело бы к потери памяти в этой странице, поскольку
при размещении в ней k
кортежей очень маленького размера пропадало бы место в области
хранения кортежей, а при размещении p<k
крупных
кортежей полностью заполнялась бы область хранения кортежей, но
пропадало бы место в области описателей. Для динамического
распределения памяти внутри страницы память на описатели кортежей
выделяется вниз от начала страницы, а память для хранения кортежей –
вверх от конца страницы.
Второй
вариант хранения кортежей возникает в том случае, когда некоторый
кортеж после своего создания был размещен системой в странице с
номером N,
а после обновления с увеличением размера перестал помещаться в этой
странице, и система была вынуждена разместить его в странице с
номером M.
Тогда исходный tid этого кортежа не изменится, но его описатель в
странице N
будет содержать не координаты кортежа в данной странице, а новый
tid, указывающий на реальное положение кортежа в странице M.
Легко видеть, что применение такого подхода позволяет ограничиться
максимум одним уровнем косвенности (если данный кортеж в какой-то
момент времени перестанет помещаться в странице M,
и система переместит его в страницу P,
то достаточно будет изменить косвенную ссылку на этот кортеж в
странице N,
и его исходный tid
не изменится).
Поскольку
допускается нахождение в одной странице данных кортежей разных
таблиц, каждый кортеж должен, кроме содержательной части, включать
служебную информацию, идентифицирующую таблицу, которой принадлежит
данный кортеж. Кроме того, в System R (точнее, в языке SQL)
допускается динамическое добавление полей к существующим таблицам.
При этом реально происходит лишь модификация описателя таблицы в
таблице-каталоге таблиц. В существующем кортеже таблицы новое поле
возникает только при модификации этого кортежа, затрагивающей новое
поле. Это позволяет избежать массовой перестройки хранимой таблицы
при добавлении к ней новых полей, но, естественно, требует хранения
при кортеже дополнительной служебной информации, определяющей
реальное число полей в данном кортеже. (Заметим, что удалять
существующие поля существующей таблицы в SQL System R не
разрешалось.)
Индексы и кластеризация таблиц
На
основе наличия уникальных, обеспечивающих почти прямой доступ к
кортежам и не изменяемых во время существования кортежей tid'ов в
System R поддерживаются дополнительные управляющие структуры –
индексы. Каждый индекс определяется на одном или нескольких полях
таблицы, значения которых составляют его ключ, и позволяет
производить прямой поиск по ключу кортежей (их tid'ов) и
последовательное сканирование таблицы по индексу, начиная с
указанного ключа, в порядке возрастания или убывания значений ключа.
Некоторые индексы при их создании могут обладать атрибутом
уникальности. В таком индексе не допускаются дубликаты ключа. Это
единственное средство SQL System
R
указания системе первичного ключа таблицы (фактически, набора
первичного и всех возможных ключей таблицы).
Для
организации индексов в System R применяется техника B+-деревьев
(более подробно B+-деревья
рассматриваются в подразделе 12.3.2. Индексы).
Каждый индекс занимает отдельный набор страниц, номер корневой
страницы запоминается в описателе индекса. Использование B+-деревьев
позволяет достичь эффективности при прямом поиске, поскольку они
из-за своей
сильной
ветвистости обладают небольшой глубиной. Кроме того, B+-деревья
сохраняют порядок ключей в листовых блоках иерархии, что позволяет
производить последовательное сканирование таблицы в порядке
возрастания или убывания значений полей, на которых определен
индекс. Фундаментальное свойство B+-деревьев – автоматическая
балансировка дерева – допускает произведение лишь локальных
модификаций индекса при переполнениях и опустошениях страниц
индекса. Насколько известно автору, System R была первой системой, в
которой для организации индексов использовались B+-деревья. Эту
традицию соблюдает большинство реляционных систем, возникших
позднее.
Видимо,
наиболее важной особенностью физической организации баз данных в
System R является возможность обеспечения кластеризации связанных
кортежей одной или нескольких таблиц. Под кластеризацией кортежей
понимается физически близкое расположение (в пределах одной страницы
данных) логически связанных кортежей. Обеспечение соответствующей
кластеризации позволяет добиться высокой эффективности системы при
выполнении некоторого
класса запросов.
В силу большой важности понятия кластеризации в System R и ее
развитиях рассмотрим историю вопроса более подробно.
В окончательном
варианте System R существует только одно средство определения
условий кластеризации таблицы – объявить до заполнения таблицы
один (и только один) индекс, определенный на полях этой таблицы,
кластеризованным. Тогда, если заполнение таблицы кортежами
производится в порядке возрастания или убывания значений полей
кластеризации (в зависимости от атрибутики индекса), система
физически располагает кортежи в страницах данных в том же порядке.
Кроме того, в
каждой странице данных кластеризованной таблицы оставляется
некоторое резервное свободное пространство. При последующих вставках
кортежей в такую таблицу система стремится поместить каждый кортеж в
одну из страниц данных, в которых уже находятся кортежи этой таблицы
с такими же (или близкими) значениями полей кластеризации.
Естественно, что поддерживать идеальную кластеризацию таблицы можно
только до определенного предела, пока не исчерпается резервная
память в страницах. Далее этого предела степень кластеризации
таблицы начинает уменьшаться, и для восстановления идеальной
кластеризации таблицы требуется физическая реорганизация таблицы (ее
можно произвести средствами SQL).
Очевидным
преимуществом кластеризации таблицы является то, что при
последовательном сканировании кластеризованной таблицы с
использованием кластеризованного индекса потребуется ровно столько
чтений страниц данных из внешней памяти, сколько страниц занимают
кортежи этой таблицы. Следовательно, при правильно выбранных
критериях кластеризации запросы, связанные с заданием условий на
полях кластеризации можно выполнить почти оптимально.
В
ранних версиях System R существовал еще один способ физического
доступа к кортежам таблицы и, соответственно, еще один способ
указания условия кластеризации с использованием так называемых
связей (links). На уровне физического представления связь –
это физическая ссылка (tid) из одного кортежа на другой (не
обязательно одной таблицы). В языке SEQUEL
(до того момента, когда его стали называть SQL) существовали
средства определения связей в иерархической манере: можно было
объявить некоторую таблицу родительской по отношению к той же или
другой таблице-потомку. При этом указывались поля родительской
таблицы и таблицы-потомка, в соответствии со значениями которых
образовывалась иерархия. Правила построения были очень простыми –
проводились связи от кортежа родительской таблицы ко всем кортежам
таблицы-потомка с теми же значениями полей связывания. На самом
деле, все кортежи таблицы-потомка с общим значением полей связывания
образовывали кольцевой список, на который проводилась одна связь из
соответствующего кортежа родительской таблицы.
Следует заметить,
что этот способ использования механизма связей поддерживался в
ранних версиях SEQUEL. В интерфейсе RSS System R этого периода
допускалась возможность произвольной установки связей без учета
совпадения значений полей связывания. Тем самым, в системе в целом
не использовались все возможности RSS, которые с избытком
превосходили потребности организации иерархических бинарных связей
по совпадению полей связывания.
Для одной таблицы
допускалось создание многих связей: кортеж таблицы мог быть
родителем нескольких иерархий и входить в несколько других иерархий
в качестве потомка. При этом одна связь могла быть объявлена
кластеризованной. Тогда система стремилась поместить в одну страницу
данных все кортежи одной иерархии. При этом, естественно,
использовалась возможность размещения в одной странице данных
кортежей нескольких таблиц. Основной смысл такой кластеризации
заключался в возможности оптимизации выполнения некоторых запросов,
включающих (экви)соединение двух связанных таблиц в соответствии со
значениями полей связывания.
В
более поздних публикациях, посвященных System R, упоминания о
механизме связей исчезли, из чего можно заключить, что разработчики
отказались от его использования. Думается, что основными причинами
отказа от использования связей были следующие. Во-первых, средства
построения связей, обеспечиваемые RSS, были очень низкого уровня,
гораздо более низкого, чем средства поддержки
индексов. Если при занесении, удалении или обновлении кортежа RSS
обеспечивала автоматическую коррекцию всех индексов, то для
коррекции связей требовалось выполнить ряд дополнительных обращений
к RSS, из-за чего время выполнения этих операций, конечно,
увеличивалось.
Во-вторых, при
реализации этого механизма возникают дополнительные
синхронизационные проблемы нижнего уровня (уровня совместного
доступа к страницам данных). В частности, наличие прямых ссылок
между страницами данных увеличивает вероятность возникновения
синхронизационных тупиков.
Наконец, в-третьих,
все эти дополнительные накладные расходы не окупались
преимуществами, предоставляемыми механизмом связей. Действительно,
максимального эффекта от использования связей можно достичь только
при выполнении операции соединения двух таблиц, кластеризованных по
этой связи, если поле соединения совпадает с полем связывания и
условия, накладываемые на родительскую таблицу, выделяют в нем ровно
один кортеж. Очевидно, что такие запросы на практике редки.
(Отметим, что
приведенные соображения принадлежат автору и не излагались в
публикациях по System R, так что на самом деле причины могли быть и
другими.)
Кроме
таблиц и индексов при работе System R во внешней памяти могут
располагаться еще и временные объекты – списки (list). Список
–
это временная структура данных, создаваемая с целью оптимизации
выполнения SQL-запроса,
содержащая некоторые кортежи хранимой таблицы базы данных, не
имеющая имени и, следовательно, не видимая на уровне интерфейса SQL.
Кортежи списка могут быть упорядочены по возрастанию или убыванию
полей соответствующей таблицы. Средства работы со списками имеются в
интерфейсе RSS, но их, естественно, нет в SQL. Соответственно, эти
средства используются только внутри системы при выполнении запросов
(в частности, один из наиболее эффективных алгоритмов выполнения
соединений основан на использовании отсортированных списков
кортежей). Публикации по System R не дают точного представления о
структурах данных, используемых при организации списков, но исходя
из здравого смысла можно предположить, что они устроены не так, как
таблицы (например, для кортежа, входящего в список, не требуется
адресация через tid), и что располагаются они во временных файлах (в
случае сбоя системы все временные объекты пропадают).
Назад Содержание Вперёд