Архитектуры ООСУБД. Анализ реализаций


Следствия модели запросов


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

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

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

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

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

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



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

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

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

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



Так что замечание Грина о том, что «запросы могут адресоваться только к объектам, входящим в специальные коллекции», в действительности является довольно бессмысленным; аналогично можно было жаловаться на то, что в реляционных базах данных запросы могут адресоваться только к таблицам.


Кроме того, это в любом случае неверно, поскольку в ObjectStore поддерживаются произвольные запросы через динамические экстенты.

Интересным побочным аспектом является смысл объектов, не имеющих родителей. Объекты-сироты, присутствующие в базе данных ObjectStore, – это объекты, на которые отсутствуют ссылки из других объектов. Это значит, что никакая программа не может получить доступ к этим объектам, кроме как путем использования объектного курсора. Если считать, что используется навигационный доступ, как это и рекомендуется, то наличие этих осиротелых объектов утечки персистентной памяти (memory leak); клиентский код не может удалить более не нужный объект.

«Можно представить себе ситуацию, в которой имеется миллион объектов Foo, среди которых ищется всего один объект. Вдобавок к этому при каждой вставке требуется поддержка индексов, а поскольку потенциально они могут быть распределены между многими клиентскими процессами, может возникнуть много недействительных страниц, и понадобятся сетевые обновления коллекций и индексов, дополнительно нагружающие сеть.»

В правильно спроектированной системе, основанной на ObjectStore, нахождение единственного объекта Foo в коллекции из миллиона объектов обычно является очень быстрым вызовом. Для этого не требуется какая-либо работа программистов!

Здесь Грин рисует очень неточную картину поддержки индексов в ObjectStore. При вставке объекта в индексируемую коллекцию инициируется автоматическая поддержка индекса. В представленном сценарии, в котором одиночный объект Foo вставляется в коллекцию из миллиона объектов, будет обновляться одна страница индекса, или, может быть, несколько страниц. При фиксации транзакции ObjectStore (в предположении, что фиксация выполняется) страницы, содержащие индексные структуры данных, возвращаются на сервер и записываются на диск, как и любые другие страницы. Если к индексу обратится другой клиент, эти несколько страниц будут выдаваться обычным образом страница за страницей. Измененные индексные страницы пересылаются только в тех случаях, когда они используются другими клиентами, и никакие другие страницы, например, те, которые содержат миллион объектов Foo, не пересылаются в результате обновления этого индекса.



« Кроме того, многопотоковая организация клиентского процесса позволят выполнять запросы к нескольким физическим базам данных в параллель.»

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

«При использовании систем с архитектурой, основанной на страницах …, управление индексами обычно интегрируется с кодом приложений. Это влияет на сопровождение приложений. При использовании систем с архитектурой, основанной на объектах, индексы управляются сервером. Новые индексы могут определяться без изменения приложений.»

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


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

Неверно также и то, что в ObjectStore нельзя определять индексы без изменения приложения, поскольку эта функциональная возможность может быть обеспечена путем написания дополнительного специального приложения поддержки индексов. API для добавления индексов является очень простым и ориентированным на программистов C++. Определить новый индекс в ObjectStore не сложнее, чем написать операторы DDL для добавления индексов над реляционными таблицами. Поэтому относительно просто написать автономное приложение для добавления или уничтожения индексов над любой коллекцией базы данных, даже если система используется другими приложениями, и эти приложения смогут начать использовать заново созданные индексы сразу после фиксации транзакции, в рамках которой они были созданы. Так что индексы в ObjectStore можно создавать и удалять динамически, «на лету» без изменения кода основных приложений.


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