On-Line Библиотека www.XServer.ru - учебники, книги, статьи, документация, нормативная литература.
       Главная         В избранное         Контакты        Карта сайта   
    Навигация XServer.ru






 

Особенности внутренней организации таблиц

Введение

Еще 6 лет назад для покупателя при выборе настольной СУБД решающим фактором было, работает-ли продукт с таблицами формата DBF, или нет. Приизводители также стояли перед выбором - делать свой продукт xBase-совместимым по формату данных, и попасть в "тискаи" устаревшего формата, либо использовать собственный формат данных и обречь себя на трудности в борьбе с продавцами xBase. Если продукт работал с собственным форматом, то наличие импорта/экспорта DBF было обязательням. Но с течением времени объем информации рос, и технология импорта/экспорта становилась все более неудобной. Такое положение дел долго продолжаться не могло, и в 1991 году Borland объявил о том, что вскоре выпустит IDAPI - Intergrated Database API, ядро доступа к БД, которое будет обеспечивать универсальный доступ к форматам настольных СУБД. Microsoft также объявил о выпуске Open DataBase Connectivity - универсального SQL-интерфейса к различным форматам данных. ODBC на текущий момент является подмножеством IDAPI, т.к. не реализует навигационный интерфейс к БД. Это весьма существено, потому что количество приложений, написанных в "навигационном" стиле довольно велико, и не может быть быстро переделано на доступ при помощи SQL-языка.

В настоящее время IDAPI реализован в BDE - Borland Database Engine. BDE определяет набор функций, при помощи которых можно осущетсвлять доступ к данным независимо от из формата - как навигационным способом, так и при помощи SQL-выражений. BDE используется во всех последних продуктах Borland - Delphi, dBase V for Windows, Paradox 5.0 for Windows, Borland C++ & Database Tools а также в виде отдельного продукта.

В базовую поставку любого продукта с BDE обязательно входят два драйвера - для таблиц dBase и Paradox. При использовании доступа к данным через SQL-выражения эти форматы выглядят одинаково. Но в части навигационного доступа они несколько отличаются. Borland приложил все усилия, чтобы оставить функциональность обоих форматов, в результате BDE содержит несколько функций, которые работают или только с одним форматом, или работают по разному в зависимости от формата. Подавляющее большинство функций BDE работают независимо от формата данных, будь то локальные таблицы, ODBC-данные или таблицы SQL-сервера (через SQL-Link).

Теперь рассмотрим форматы dBase и Paradox отдельно, чтобы учесть особенности каждого. В дальнейшем, при разработке приложения, Вы сами решите - использовать эти особенности или попытаться их избежать.

Формат dBase

Этот формат представляет собой обычный плоский файл *.DBF. Записи расположены в порядке добавления, поскольку новые записи помещаются всегда в конец файла. Если Вы хотите просматривать записи в порядке, отличном от естественного, то Вы должны построить индекс. Индекс имеет структуру B-дерева, элементами которого являются ключевые значения и номера соответствующих записей в DBF-файле. Таким образом, при поиске или просмотре данных по индексу, из индекса берется номер записи, соответствующий конкретному значению ключа, и осуществляется выборка нужной записи из DBF-файла. Если в индексе ключевые значения расположены последовательно, то соответствующие им записи в DBF - произвольно, и при таком способе доступа происходят частые перемещения по файлу с записями, что безусловно замедляет работу (например FILTER в Clipper) и более того, при больших объемах данных делает работу аппаратного или программного кэша практически бесполезной (кэш в этом случае помогает только индексу).

Для удаления записей применяется следующий подход - чтобы не оставлять "пустоты" в файле записей, при удалении первый байт записи принимает специальное значение, индицирующее, что запись удалена. Такие записи исключаются из просмотра, и как-бы отсутствуют. Безусловно, есть средства, позволяющие просматривать таблицу и с удаленными записями, а также восстанавливать их (отменять флаг удаления).

Номера записей остаются соответствующими физическим, и если удалена запись N 5, то при просмотре подряд идут записи с номерами 4 и 6.

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

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

Для иллюстрации перечисленных особенностей смотрите пример EX1.DPR.

Формат Paradox

Этот формат был специально разработан для настольной СУБД, использующей правила (некоторые) реляционной модели БД. По этим правилам таблица должна иметь первичный ключ, уникально идентифицирующий записи. Таблица, не имеющая первичного ключа - редкое исключение.

Файл DB имеет страничную организацию - записи распределены по страницам (блокам) фиксированного размера (1, 2 или 4 Кбайт), и при наличии первичного ключа отсортированы в порядке ключа. Первичный ключ находится в отдельном файле (*.PX) и содержит в качестве элементов ключевые поля первой записи каждого блока DB-файла и номер этого блока. Таким образом, поиск по значениям первичного ключа идет как в B-дереве - ищется подходящая страница в файле PX, а затем нужная запись в странице DB-файла.

Добавление или вставка записей происходит всегда в правильную позицию - в порядке первичного ключа. Номера других записей при этом могут меняться, но радикального изменения индекса это не требует, т.к. тот хранит только ссылки на страницы, а не на сами записи (именно поэтому файл PX имеет размер намного меньше размера соответствующего файла DB). При удалении записи она удаляются, и последующие записи в странице переносятся на ее место. Затирания может и не произойти, если запись является последней на странице, но запись о блоке в первичном индексе хранит и информацию о количестве записей в этом блоке, поэтому восстановить удаленную запись все-равно будет невозможно.

Вторичные ключи могут быть построены только при наличии первичного, т.к. они основываются на первичном ключе. В общем первичный ключ представляет собой пару DB-PX, только имеет другие расширения (x??-y??, или композитные xg?-yg?), и другие поля. Поля записи вторичного ключа содержат: как первичный ключ - поле (или поля), по которому построен вторичный ключ + поля первичного ключа самой таблицы (DB), номер блока с записью в таблице (см. далее о пакетных индексах).

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

Вторичные индексы бывают двух типов - автоматические и пакетные (maintained и nonmaintained). Автоматические индексы это те, которые перестраиваются немедленно при модификации таблицы. Поскольку ключ в автоматическом индексе ссылается не на запись а на блок, где она расположена, то при перестройке индекса меняется минимум информации и происходит минимум обращений к DB-файлу. Пакетные индексы вместо ссылок на первичный индекс и блок хранят непосредственные ссылки на записи в файле DB. В результате они позволяют осущетсвлять очень быстрый поиск, но становятся "бракованными" при любой модификации таблицы. Это дает возможность для оперативномго поиска при периодических модификациях использовать автоматические индексы, перестраивание которых несколько замедляет работу с БД, а для пакетных модификаций (группами записей) использовать пакетные индексы, которые "отключаются" на время модификации и не перестраиваются до первого поиска по такому индексу.

Несмотря на то, что для формата Paradox при каждом изменении таблицы перестраиваются все автоматические индексы (включая первичный), это не замедляет работу настолько, насколько ожидается. Дело в том, что данные в записях хранятся в двоичном виде, и более того, сконвертированы в форму, максимально облегчающую построение индексов (например по числовым полям). В DBF-формате данные хранятся в строковом представлении, и тоже могут быть проиндексированы без преобразования, но занимают намного больше места на диске, а значит и требую больших расходов памяти. Например число, хранимое в DB как 8 байт (numeric), в DBF заняло-бы минимум 18 байт.

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

Нумерацию записей в порядке текущего индекса трудно назвать недостатком, однако в результате модификация таблицы происходит дольше. Закладки стабильны только для конкретного индекса, т.к. опираются на значение текущего ключа, а не номер записи (и будут стабильны пока существует этот индекс, в то время как при упаковке DBF закладки перестанут быть актуальными).

Для иллюстрации перечисленных особенностей смотрите пример EX2.

Еще одна особенность "закрытости" формата Paradox в том, что он позволяет обеспечивать семантическую и ссылочную целостность данных на уровне ядра IDAPI (BDE). Достаточно определить при создании или реструктуризации таблицы пункты Validity Checks и Referental Integtity, и BDE будет сам отслеживать правильность значений полей таблицы независимо от того, каким способом Вы открываете эту таблицу (эти данные находятся в файле *.VAL). Validity Checks обеспечивает контроль максимального, минимального, умолчательного значений поля, а также соответствие введенного значения некоторому шаблону. Referental Intergity позволит установить связь между полями таблиц (master- detail), и будет контролировать измения значений связанных полей даже если приложение открыло всего одну из связанных таблиц (напр. при изменении кода заказчика в таблице заказчиков он будет корректно изменен у всех связанных с этой записью записей в таблице заказов).

Такие свойства (первичный ключ, контроль полей, контроль ссылочной целостности) позволяют приблизить моделирование данных с использованием таблиц Paradox к моделированию данных в SQL-серверах, и облегчить последующий перенос данных или. Формат DBF этому не способствует ни в коей мере, поэтому у чаще всего именно у программистов, работавших на Clipper, возникают проблемы при переходе на SQL-серверные технологии.

Вышеописанный формат кроме достоинств имеет и ряд побочных эффектов. Один из тех, с которым часто сталкиваются - страничная организация DB-файла: Когда создается таблица, BDE выбирает размер страницы оптимальным образом по размеру записи (запись также не может пересекать границу страницы, а следовательно быть более 4К). Допустим, что у нас получилась таблица с размером страницы 2К. Затем, если реструктуризировать таблицу, и начать добавлять новые поля, размер записи может превысить существующий размер страницы и таблица не будет реструктуризирована (сообщение об ошибке). Причина понятна - существующий размер страницы не может быть изменен.

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

Хочу добавить, что раньше существовала проблема восстановления испорченных данных - это было возможно только при помощи Paradox 5.0 for Windows - он содержит TUTILITY.DLL, при помощи которого можно исправить таблицы. Недавно ДемоЦентром был получен архив с TUTILITY.DLL, интерфейсом использования (4 компоненты для Delphi) и программой-примером.

Заключение

У обоих форматов есть и достоинства, и недостатки. Благодаря BDE (IDAPI) Вы можете выбрать формат, который Вам больше по душе, или перейти с одного на другой.

DBF дает Вам совместимость практически со всеми xBase-продуктами, но ограничивает в выборе типов полей для хранения данных.

DB является закрытым форматом, т.е. кроме библиотек Borland ничего с этим форматом правильно не работает. Однако DB предоставляет широкий набор типов полей включая поля BLOb с произвольным доступом к любой части BLOb, контроль ссылочной и семантической целостности данных на уровне ядра BDE.

Надеюсь, что данная статья помогла вам понять особенности этих форматов, и учесть это в своих программах.



Литература по DBase