Олег Федоров

 

9 декабря 1997 г. Interbase Software Corporation объявила о выходе пятой версии своего популярного SQL-сервера. Это событие не сопровождалось всем уже порядком поднадоевшими рекламными заявлениями о революционности нового продукта, о том, что новая версия кардинально изменит существующее на сегодняшний день положение вещей в своей отрасли, и т. д. За время работы в индустрии ПО я научился относиться к таким словам с изрядной долей скептицизма, а иногда и подозрительности, ибо существенные изменения в программном продукте неотвратимо влекут за собой новые ошибки. Все мы помним, как непросто прошел переход на версию 4.2, в которой впервые была применена архитектура SuperServer.

В этом плане ситуация с появлением InterBase 5.0 (или IB Database 5.0) сложилась достаточно благоприятная: разработчики обращали внимание больше на исправление старых ошибок и недоработок, нежели на принципиальные нововведения.

Сразу хочу сказать, что я работал только с версиями для Windows 95 и NT и речь пойдет о них.    

 

Архитектура SuperServer

Версия 5.0, принимая эстафету от предыдущей версии 4.2, также имеет суперсерверную архитектуру. Это означает, что на каждого нового клиента сервер запускает отдельный поток, а не процесс, как принято в классической архитектуре. Такой подход дает целый ряд преимуществ. Во-первых, отпадают трудности с диспетчеризацией равноправных процессов друг другом, из-за которых в версии 4.0 серверный процесс продолжал “работать” и тратить процессорное время при обрыве связи с клиентом. Во-вторых, взаимодействие между нитями одного процесса гораздо проще и быстрее, нежели между разными процессами. В-третьих, появляется возможность организовать “умное” кэширование данных на уровне СУБД для нескольких соединений сразу. В-четвертых, накладные расходы на открытие нового потока всегда меньше, чем на запуск нового процесса. Кроме того, снижаются требования к системным ресурсам и поддерживается большое число одновременно работающих клиентов.

Суперсерверная архитектура также позволяет уменьшить вероятность нарушения целостности базы данных, так как можно дать права на запись в БД только одному серверному потоку, защищенному от сбоев в пользовательских приложениях (что и сделано в InterBase 5.0). При этом отпадает необходимость арбитража при доступе к разделяемым страницам базы данных.

Правда, как всегда случается в реальной жизни, есть и некоторые негативные моменты в таком подходе. К ним можно отнести потенциальное снижение пропускной способности при работе с базой данных. Это происходит из-за того, что все клиентские потоки при возникновении необходимости обращения к БД вынуждены ждать освобождения вышеописанной серверной подсистемы, отвечающей за взаимодействие с базой. Конечно, эта проблема несущественна при относительно низкой нагрузке на сервер и, по моему разумению, для задач, в которых принято применять SQL-сервера, лучше уж небольшое снижение производительности за счет значительного увеличения надежности, чем наоборот. К тому же разница во временах отклика серверов суперсерверной и “классической” архитектур при прочих равных условиях сильно зависит от эффективности реализации арбитража страниц БД в последней. Но разработчикам крупных ИС с большой нагрузкой стоит помнить об этой особенности.

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

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

Надежность

Сразу видно, что разработчики InterBase уделили большое внимание исправлению ошибок предыдущей версии. Исправлена ошибка с постоянным “отъеданием” памяти, из-за которой версия 4.2 была неспособна работать под более-менее серьезной нагрузкой длительное время без перезапуска. Версия 5.0, по моим наблюдениям, в этом отношении работает весьма стабильно.

Кроме того, в качестве дополнительной меры повышения отказоустойчивости сервера в дистрибутив версии 5.0 входит InterBase Guardian - специальный процесс, следящий за работой сервера и перезапускающий его при возникновении ошибки или в любом другом случае аварийного завершения работы сервера. По умолчанию Guardian стартует автоматически при загрузке ОС и запускает вместе с собой сам сервер. Но при необходимости вы можете изменить режим запуска на ручной, пользуясь программой InterBase Configuration, входящей в комплект поставки. Можно даже запретить использование Guardian (хотя я не представляю, для чего это может понадобиться).

По умолчанию при создании новой БД для нее включен режим немедленной записи (forced writes). Это означает, что серверный процесс записывает данные на диск сразу после подтверждения изменяющей их транзакции. Таким образом в базе всегда находится целостная непротиворечивая информация. Однако такой режим работы не использует кэширование изменений, что замедляет обращение к БД примерно в 5 - 6 раз. Вы можете выключить немедленную запись для конкретной базы из InterBase Server Manager, но я бы не рекомендовал делать это в случае, если ваш компьютер не оборудован источником бесперебойного питания и/или к нему имеют доступ не вполне квалифицированные сотрудники. Но если вы все же решились воспользоваться данной возможностью и увеличить производительность сервера, то примите меры к регулярному, хотя бы раз в день, резервному копированию базы.

Если ваша задача предъявляет повышенные требования к надежности, рекомендую задействовать возможность зеркалирования БД. На языке IB Database такая копия БД называется “тенью” (shadow). Все операции записи, производимые над основной базой, параллельно производятся и над shadow-базой. В случае сбоя в основной БД она заменяется на shadow без какой-либо потери данных. Но так как зеркалирование требует дополнительного времени, рекомендуется размещать файлы основной и shadow-базы на разных физических дисках. И лучше, чтобы они были подключены к разным контроллерам. Так вы добьетесь от сервера максимальной производительности при максимальной отказоустойчивости.

В InterBase 5.0 исправлена ошибка, долгое время не дающая спокойно жить любителям самостоятельно оптимизировать запросы, не полагаясь на встроенный оптимизатор. Как известно, InterBase дает такую возможность с помощью явного указания списка индексов, используемых для отбора/сортировки данных. Это называется планом (PLAN) запроса. Проблемы возникали при восстановлении базы из резервной копии. Если база содержала хранимые процедуры с явным указанием плана запроса, то из-за того, что индексы восстанавливались позже хранимых процедур, такие процедуры не могли быть корректно восстановлены.

Из приятных мелочей не могу не отметить: при вычислении SQL-выражений MIN и MAX наконец-то стали использоваться индексы. И еще отечественные разработчики больше могут не утруждать себя напоминанием пользователям о том, что для корректной работы с русскоязычными данными IB надо ставить в каталог, не содержащий пробелов и длинных имен. Даже при установке в каталог, предлагаемый инсталлятором по умолчанию, версия 5.0 корректно работает с базами, созданными в кодировке WIN1251.

Удостоверившись, что с надежностью у InterBase 5.0 все более-менее в порядке, можно задать вполне закономерный вопрос: не досталась ли эта надежность за счет снижения производительности?    

Производительность и способы ее повышения

Первое, что замечаешь при работе новой версии - значительное (примерно на порядок) ускорение операции DISTINCT. При ближайшем рассмотрении выяснилось, что также ускорены операции ORDER BY и GROUP BY. Это сделано с помощью эффективного использования индексов, аналогично повышению быстродействия MAX() и MIN().

Базы данных, создаваемые версией 5.0, имеют отличную от предыдущих версий структуру хранения информации на диске (On-Disk Structure, сокращенно ODS). Хотя ODS 8.2 также поддерживается, но она не позволяет использовать некоторые нововведения, например каскадную ссылочную целостность, сборку мусора для индексов и SQL-роли. Для обновления структуры уже имеющихся у вас баз нет необходимости создавать их заново, достаточно лишь последовательно произвести для них операции создания резервной копии и восстановления из нее.

Автоматическая сборка мусора для индексов является одной из тех приятных мелочей, о которых я писал в начале статьи. Она не является определяющей для продукта в целом, но в то же время реально увеличивает его производительность и продолжительность работы. Ранее сборка мусора для индексов выполнялась только при восстановлении базы из резервной копии, из-за этого визуально можно было наблюдать эффект “деградации” базы: чем многочисленнее изменения индексируемых полей, тем ниже эффективность использования соответствующих индексов. Это было следствием применяемого в IB механизма множественных поколений записей. Если не вдаваться в технические подробности, суть этого механизма сводится к тому, что новые данные не затирают старые, а дописываются к ним. Такой подход помимо видимых преимуществ имеет и отрицательные последствия: большое количество изменений замедляет выполнение запросов по этим данным. Происходит это из-за увеличения затрат времени на поиск актуальных на текущий момент данных. Процедура сборки мусора удаляет устаревшие данные, тем самым повышая эффективность работы с БД.

Стремясь как можно больше приблизить диалект InterBase-SQL к стандарту ANSI SQL’92, разработчики ввели в язык описания данных (Data Definition Language, DDL) возможность определения декларативной каскадной ссылочной целостности. Благодаря этому теперь нет необходимости писать дополнительные триггеры на обновление и удаление данных в мастер-таблице и синхронизировать эти изменения с подчиненными таблицами. Закон поведения в таких ситуациях можно записать прямо при создании таблички.

IB Database 5.0 содержит средства для назначения прав группам пользователей. В терминах диалекта InterBase-SQL такие группы называются ролями (role) и создаются оператором CREATE ROLE <RoleName>. После создания названия групп (ролей) могут использовать в операторах GRANT и REVOKE как имена обычных пользователей. Необходимость в Interbase такого средства давно ощущалась администраторами БД и породила множество продуктов сторонних разработчиков.

В версии 5.0 появились новые ключевые слова: ACTION, ADMIN, CASCADE, RESTRICT, ROLE, FREE_IT. Все они (за исключением FREE_IT) связаны с описанными выше новшествами. Поэтому при обновлении Interbase будьте внимательны: если ваши метаданные (названия таблиц, полей, etc.) содержат эти слова, необходимо изменить такие названия до установки IB Database 5.0.

Одной из особо примечательных возможностей InterBase всегда было использование функций, написанных на любом языке программирования третьего поколения, поддерживающем тип вызова cdecl. Такие функции называются UDF (User-Defined Functions) и позволяют получить нужную функциональность непосредственно на сервере, под который обычно отводится более мощный компьютер. В комплект поставки версии 5.0 входит стандартная библиотека из наиболее широко используемых математических и строковых функций. Нетрудно догадаться, что неаккуратное обращение с механизмом UDF может повлечь за собой порчу данных, а в суперсерверной архитектуре - и сбои в работе самого сервера. Для обеспечения большей надежности при написании многопотоковых UDF в InterBase 5.0 введено новое ключевое слово FREE_IT. После вызова функции, описанной с параметром FREE_IT, InterBase автоматически освобождает память, выделенную внутри функции.

Один широко известный литературный персонаж утверждал, что единственной полезной структурой данных является массив. IB Database позволяет создавать поля типа массива, элементами которого являются любые стандартные типы данных, за исключением BLOB. Эта специфическая возможность может заметно повысить коэффициент полезного действия вашего труда для определенного круга задач.

Теперь перейдем к рекомендациям по повышению производительности сервера InterBase 5.0. Прежде всего, необходимо выбрать размер страницы базы данных из предлагаемых значений: 1024 (это размер страницы по умолчанию), 2048, 4096 и 8192 байт. Выбор будет сильно зависеть от предполагаемой структуры БД: числа таблиц, полей, индексов и т. д. По своему опыту могу сказать, что в реальных системах среднего уровня, не совсем маленьких, но и не очень больших, оптимальным является страница в 4096 байт. Впрочем, если в ваших табличках много данных типа BLOB или просто большое количество полей в записи, то можно попробовать установить размер страницы в 8192 байт. Причем IB дает возможность сменить размер страницы при восстановлении базы из резервной копии, так что для выбора вам нет необходимости каждый раз создавать БД заново и наполнять ее данными.

Выбрав размер страницы, можно перейти к настройке кэша сервера InterBase. Значение этого параметра указывается в страницах и зависит в основном от объема памяти и от того, как будет применяться компьютер, на котором установлен IB. Если планируется сделать компьютер выделенным сервером БД, то можно попробовать увеличить размер кэша с предлагаемых по умолчанию 256 страниц до 1024.

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

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

Наконец, если в вашей базе большое количество метаданных (таблиц, полей и других объектов), имеет смысл создать индексы по некоторым полям системных таблиц для повышения скорости доступа к ним. Рекомендуется следить за эффективностью использования индексов, периодически просматривая статистическую информацию о базе данных (для этого служат пункты меню Database Statistics и Database Analysis) в InterBase Server Manager. Там кроме общих параметров базы можно получить информацию о степени заполнения табличек и глубине индексов. Глубина индекса (index depth) - это то же самое, что глубина двоичного дерева. Нормальными считаются значения до 3 включительно. Если глубина вашего индекса больше, имеет смысл его перестроить, воспользовавшись последовательным выполнением SQL-предложений

ALTER INDEX <IndexName> INACTIVE;

ALTER INDEX <IndexName> ACTIVE.

Если это не поможет, попробуйте сделать резервную копию, а затем восстановить базу из нее. Критичным также является максимальное количество повторяющихся значений индексирумого поля (max dup). Если этот параметр сопоставим с 1/3 всех записей в табличке, то стоит задуматься о том, нужен ли такой индекс вообще. Получить оптимальный набор индексов можно, выполняя реальные запросы, применяемые в вашей задаче, в утилите WISQL с включенной опцией Show query plan.

Хоть InterBase 5.0 и не умеет индексировать поля типа BLOB (что, впрочем, естественно), но зато он дает возможность делать поиск по таким полям аналогично поиску по полям типа CHAR и VARCHAR, пользуясь обычными SQL-операторами LIKE и CONTAINING. Эта примечательная особенность позволяет значительно снизить нагрузку на сеть при реализации полнотекстового поиска в документах, ведь в противном случае мы были бы вынуждены тянуть все данные на клиентский компьютер и только там производить их фильтрацию, что, кстати, противоречит технологии клиент-сервер.

Для еще большего снижения нагрузки на сеть IB предлагает уникальную технологию сигнализаторов событий (event alerters). Представим себе такую ситуацию: есть табличка сообщений, служащая специально для общения разных модулей программного комплекса друг с другом. Соответственно всем модулям надо реагировать на ее изменение. Классическая схема решения такой задачи выглядит следующим образом: считывание новых данных активизируется со стороны программного модуля и обычно выполняется по таймеру. Кроме дополнительной нагрузки на сеть в этом случае получаем еще и неоправданные, непонятные простому пользователю затраты на периодическое выполнение холостых запросов. Идеология IB Database кардинально отличается от классической: сервер сам должен сообщать о событиях, не требуя постоянного опроса со стороны клиента. Практически это реализуется командой:

POST_EVENT <EventName>,

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

Наконец, заканчивая тему снижения нагрузки на сеть и пойдя по пути модной нынче идеологии “тонкого” клиента, но не превращая сервер баз данных в сервер приложений, можно порекомендовать вынести на сервер максимально возможное количество вычислительных и прочих нестандартных для СУБД задач за счет использования определямых пользователем функций (UDF). Поскольку компьютер, выделенный для СУБД, обычно более мощный, нежели клиентская рабочая станция, таким образом мы решаем сразу две задачи: уменьшение трафика в сети и понижение требований к ресурсам клиентского компьютера. Тем более что благодаря суперсерверной архитектуре сама собой отпала проблема, существовавшая в версии 4.0: два серверных процесса не могли одновременно обратиться к одной UDF-функции.

Достаточно распространенными задачами являются загрузка больших объемов информации в базу и экспорт данных. Они могут возникнуть, например, при переходе с одной СУБД на другую. InterBase облегчает этот процесс, позволяя создавать так называемые “внешние” таблицы (external tables). Внешняя таблица представляет собой обычный ASCII-файл со строчками фиксированной длины (записями). Доступ к таким файлам может осуществляться с помощью любого ПО. В то же время InterBase дает возможность работать с ними, как с обычными таблицами, за несколькими исключениями:

- из-за требования фиксированности длины строки внешние таблицы не могут содержать BLOB-полей;

- на внешних таблицах нельзя выполнять операции DELETE и UPDATE;

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

Я считаю, что эти ограничения в большинстве случаев несущественны и с лихвой компенсируются теми удобствами и производительностью операций массового импорта/экспорта, которые дают внешние таблицы. Однако здесь есть еще один подводный камень, который не описан в документации по IB Database в явном виде. Заключается он в следующем. Известно, что для работы с БД, находящейся на сервере, нет необходимости давать каждому пользователю права доступа к тому диску, на котором эта база располагается. Более того, я бы настоятельно порекомендовал этого не делать в целях обеспечения отказоустойчивости и безопасности сервера. Но для доступа к внешней таблице сторонних приложений такие права должны быть, ведь внешняя таблица является обычным файлом. В этом случае наиболее подходящим решением будет помещение БД и файла внешней таблицы на разные диски.    

Ложка дегтя

Эта статья была бы неполной, и наверняка автора обвинили бы в предвзятости, без описания ошибок и недоделок InterBase 5.0. Наиболее неприятным на текущий момент фактом для меня является отсутствие документации на некоторые функции API, например на функции, выполняющие резервное копирование и восстановление баз данных. Причем если эта задача пусть не так изящно, как должна, но все же решается путем запуска программы gbak с сохранением результатов ее работы в файле, то для задач программной проверки структуры базы на ошибки и сборки мусора даже такой способ решения не подходит, так как у утилиты gfix.exe нет ключа, позволяющего записать эти самые результаты в файл, а перенаправление стандартного вывода для всех утилит командной строки IB Database не срабатывает. Видимо, для этого были свои причины, но лично мне они непонятны.

Можно возразить, что для проведения таких операций существует администратор базы данных, но, я думаю, ни для кого не секрет, что не во всех фирмах, действующих на просторах России, есть хотя бы один достаточно квалифицированный для выполнения этих функций специалист. А позиционирование InterBase на рынке как легковесной и самовосстанавливающейся СУБД дает предпосылки к его использованию в некрупных организациях.

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

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

Вероятно, из-за слишком буквального подхода к теории реляционных БД так же медленно, как и в предыдущих версиях, работает SQL-оператор COUNT().

Довольно экзотически в IB 5.0 выглядит ограничение изменений структуры таблицы числом 255. На первый взгляд такое ограничение кажется несущественным, а на мое недовольство им вполне можно сказать, что частое изменение структуры базы происходит только на стадии написания и отладки приложения; системы, находящиеся в промышленном использовании, не должны быть подвержены стольким изменениям. Увы, но мне пришлось столкнуться с задачей, для которой этот лимит оказался слишком мал. Причем только из-за недостатка, описанного в самом начале этой главы, т. е. из-за сложностей с контролем операций резервного копирования и восстановления, так как после восстановления базы из резервной копии отсчет этих 255 изменений начинается заново.

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

Документация

Дистрибутив InterBase 5.0 приятно обрадовал меня тем, что содержит онлайновую версию документации, которую можно просмотреть с помощью Adobe Acrobat Reader. Хотя читать печатную книгу намного привычнее, чем текст на экране компьютера, но для быстрого поиска информации больше подходит именно файл.

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

Java где надо и не надо

Искусственно раздутый интерес к Java заставляет всех разработчиков следовать этой моде. Не обошла участь сия и InterBase. Для версии 5.0 ISC предлагает InterClient - драйвер JDBC, написанный на чистом (pure) Java и не требующий для работы никакого дополнительного ПО кроме собственно виртуальной машины Java.    

Заключение

Новая версия Interbase Server, оставшись такой же легковесной и сохранив все свои примечательные особенности, должна привлечь внимание разработчиков высокими производительностью и надежностью. Компания Interbase Software Corporation сделала еще один шаг для закрепления своих позиций на рынке систем среднего класса. Благодаря самовосстанавливаемости сервера и оптимальному набору утилит Interbase 5.0 с указанными оговорками прекрасно подойдет организациям, которые не могут иметь в штате администратора БД.

При подготовке статьи использованы материалы с Internet-узлов: www.borland.com, www.interbasr.com.

С автором можно связаться, направив письмо по адресу: oleg@telekurs.ru.