Здравствуйте, BaZa, Вы писали:
BZ>Мне просто, например, интересно, так ли необходимо хранение методов в ООСУБД (как в Gemstone и O2)?
Когда-то в эпоху иерархий, некто господин Кодд сказал: "Ребята, у нас есть теория множеств. Над ней трудились огромное количество лет огромное количество математиков. Так что же мы х№№№№№№ страдаем. Давайте все хранить в реляционной базе, например MS SQL или Oracle и будем их оттуда выцеплять декларативным языком". И тут все завопили, Yes, That's good и т.д. Недолго думая соорудили проектик System R. И это оказалось настолько хорошо, что и придумать нельзя. И придумали декларативный язык для получения данных. И структура данных была гибкой. И лежали они в БД кортеж к кортежу. И язык оказался очень ассоциативным. И все подсели на это дело, не хуже чем на героин. Хорошее дело — взяли заказали данные, обработали и положили в базу.
И все бы хорошо. Но тут придумали ООП. Точнее даже не придумали, начали его развивать. И все завопили — Yes, That's good. На всех положим, а программы будем делать в ООП. Только надо что-то делать с хранилищем состояния объектов. Зачем нужно думать о данных, если мы работаем с объектами. Ну в ладошки поплевали, взяли топорик, ну и наломали дров. Создали несколько тестовых проектиков, описали то что есть и то что хотят. И все... А ведь дрова показали что не все спокойно в Багдаде. Проблем оказалось много. А сравнивать было с чем. С реляционкой. Построить ООБД легко, построить эффективную ООБД, нет. И основная проблема — ООП. В частности, то к чему стремились. А именно инкапсуляция и полиморфизм и навигация по объектам. И что получили из этого:
1. Ограничение на язык. При использовании правильной ООБД, данные инкапсулированы и не видны пользователю. В результате, объект должен быть реализован на определенном языке поддерживаемый ООБД. А языков в мире — море. Не только матерным живет мир. При сравнении с РСУБД можно работать практически на любом языке.
2. База данных для своего эффективного функционирования должна знать чем занимается тот или иной объект. И что от него требуется. А это нарушение полиформизма. Что для многих языков вообще было невозможно. В каждом, себя уважающем, РСУБД есть свой строго контролируемый язык и процесс компиляции в течении которого определяется, а что нужно делать для данной процедуры.
3. От хранилища данных требовали большей функциональности, чем от набора отношений. Если для РСУБД важен было упорядоченное чтение кортежей, то при навигационном доступе — не менее важно чтение по объектам.
ООБД — это существование многомерного мира в двухмерном мире винчестера. И ООБД — наличие двух видов доступа — навигационного и декларативного. А средства для увеличения эффективного доступа для обоих разные.
РСУБД праздновали победу. Кошельки пухли. Чистые объектники глотали слюну. Ну поскольку ООП развивался, а в кошельке, это дело такое, дна не бывает, то вопрос интеграции реляционной и объектной структуры решались. Началась (и продолжается) эпоха полумер. Эпоха полумер родила множество идей, всех и не перечислишь. Различные конструктивные меры перевода объектной структуры на этапе дизайна, ОРМ, CORBA, COM+, Java Beans, ОРСУБД, компромиссные ООБД, объекты с сериализацией и т.д. и т.п. Вплоть до эмуляции объектной структуры на РСУБД. Даже провели легимитизацию ОРСУБД с помощью громкого манифеста. Но ни одно решение, информацию о том, что объекты лежат в базе данных нас несчастных не оградило. Чистые ООБД, ушли в области где не может эффективно существовать реляционки.
Но время идет. Языки развиваются. Появились языки в которых можно контролировать выполнение. Оперативная память больше, процессоры и сети — быстрее а бизнес-логика сложнее. Одно плохо, во времена 1 манифеста девушки носили мини-юбки. А сейчас брюки. Весна блин. А вы все про компьютеры. Ладно, если начал то уж кончу. На данный момент сложилась ситуация в которой проблемы чистой ООБД могут быть решены. Просто еще произошло революции. Ублюдский ODMG убил идею. Через 15 лет, он довлеет над умами. Реляционка в плане развития выдыхается. Полумеры, типа внедрения вычислительно-полных языков, в саму РСУБД — не действуют и не эффективны. Верхи уже не могут, но и низы пока не хотят. Нужна искра. Нужна революция. Пролетарии всех стран, объединяйтесь!
Здравствуйте, Sinclair, Вы писали:
S>Кстати, третий подход никак не противоречит изобретению интерфейсов IVehicleOwner и IOwnedVehicle и их реализации. Если это где-то будет удобно — нет проблем.
Я вот думаю про свой доменный язык. Хочу сделать по аналогии с Helper'ами из Delphi 8 — 2005. Там же функциональность TObject заложена в helper, а доступна прямо через объект. Вот также надо, чтобы связь объявлялась отдельно, а доступна была обычным образом:
Типа объявляем так:
Первый модуль:
persistent class Customer
{
//...
}
Второй модуль:
persistent class Order
{
//...
}
В третем модуле:
persistent association CustomerOrders
{
role Customer.Orserds;
role Order.ParentCustomer;
}
А потом где-то в четвертом модуле можно использовать так:
Customer c = getCustomer(...);
int ordcnt = c.Orserds.Count;
То есть если этот четвертый модуль видит объявление ассоциации CustomerOrders, то компилятор позволяет писать прямо через точку.
Получаются зависимости:
3 -> 1
3 -> 2
4 -> 1
4 -> 2 4 -> 3
То есть такие, какие и должны быть по смыслу.
GZ>Что касается билетов. Была некоторая рекламная статья, от какой-то OODB. Какая не помню (давно было), но прикольно то что они как раз и обналичивали кассы авиабилетов. Вобщем замена Oracle на OODB дало очень большой прирост в производительности. Но чего-то сразу ее не нашел. Так что, верьте на слово.
Вот например, такая информация:
Versant in Transportation: Air France
Air France selected Versant and the Sabre Availability Processor (SAP) in 1997 to deploy a next generation yield management application to optimize global revenue by 1-2%
Versant’s object database management system was chosen because it could model a complex array of worldwide fares, inventory and schedules and calculate costs on an individual seat level, critical requirements that a relational database could not handle
Using Versant and SAP, Air France continues to generate incremental revenue streams while guaranteeing response times of under 2 seconds
“The Versant and SAP based solution extends the life of our mainframe system by processing transactions off the mainframe. The application is even faster than we expected and will generate returns that impact our bottom line.”
Pierre Gandois
Air France, Yield Management Project Manager
Versant in Transportation: British Airways
Versant ODBMS is the core database for BA’s Yield Management System used to maximize revenues. Delivered on time and within budget
Why BA selected Versant
Performance: Versant proved to be the best performing DB (40X) in benchmarks against RDBs and other ODBs
Scalability: Proven scalability of data volumes, transaction rates. 1500 flights per day vs 50 for an RDB.
24x7 capability: High availability support including online DB admin and online schema evolution, HA Backup.
Support & professional services: Highly capable and responsive support staff
Здравствуйте, GlebZ, Вы писали:
GZ>Тут ты задвинул две проблемы. Допустим у нас есть нев.. ну в общем очень большой справочник операций сделанных над документами. Операций делаются по несколько тысяч за день. Можем ли мы сохранить ссылки на операции из документов? Нет не можем. Иначе у нас получится что связи (массив OID или указателей, как тебе будет угодно) намного больше чем сам документ. То есть, проблема избыточности связей существует (что в реляционке решается нормализацией). При этом есть такая шняга, что если документ убили, операции о нем не должны исчезнуть.
Здесь я бы поставил вопрос по другому: Должны ли все связи в домейн-модели быть двунаправленные? Больной, так сказать, для меня вопрос.
GZ>Вторая проблема которую ты решил не видеть. Нам нужно найти операции просмотра с определенным документом. Ну и что тут делать? Просматривать все операции? Не лучше ли поднять индекс и сделать это весело и быстро, чем тормозить и грустно
Я так понял, что главным здесь является "операции просмотра". То есть необходимо выбрать не все, а только часть операций по определенному критерию.
Когда мы говорим о связях, которые определяются структурой объектов домейн-модели, то ИМХО мы говорим о проблемах навигационного доступа. Твой пример с выборкой операций просмотра — это ассоциативный доступ, т.е. к организации связей имеет мало отношения. Этим должен заниматься язык запросов, а это уже совсем другая тема.
И еще один хитрый вопрос — должны ли связи быть частью объекта, или же они должны быть отдельными сущностями, возможно (а может и нет) отдельно грузиться, отдельно сохраняться, а самое главное — отдельно объявляться.
Да уж. Вы практически в точку указали почему OQL нельзя использовать. Вы указали почему — построить нормальный язык очень сложно. Но вы не сказали почему все-таки производители за это не беруться, и почему они пытаются выполнять (даже в новых продуктах) требования ODMG. Мне пока не верится, что это невозможно.
Что касается оптимизации многомерных запросов, то это я пока опущу. Просто я пока не обладаю необходимыми знаниями. А работы по этому профилю есть и ведутся.
А вот что касается самого языка запросов, напишу несколько более.
Повторю свою фразу:
Запросы — это не столько получение некоторого набора объектов, а еще инструмент выполнения некоторых действий на некоторым множеством объектов.
То есть. Мы привыкли к SQL. Даже скажу больше. Мы подсели на SQL. Одной выборкой получить все данные. Поэтому, над необходимостью языка запросов для коммерческой привликательности OOБД, я думаю говорить не стоит.
Но. БД обладает некоторым свойством. И это свойство — то, что это практически единственное место где может находиться практически неогранниченное кол-во объектов. Мы привыкли к тому, что SQL служит для перегонки данных туда и обратно. Но есть также и хранимые процедуры. И у них есть величайшее свойство — они могут обрабатывать неограниченное кол-во данных. Так почему не вделать в язык то же самое.
Что этому мешает. Этому мешает то, что в отличие от хранимых процедур, где есть процедура компиляции в течении которой БД получает максимум информации для эффективного выполнения, у нас есть неподконтрольные языки. Но сейчас ситуация изменилась. Наступают управляемые языки которые не хранятся в непонятном коде зависимом от процессора, а написаны на некотором простом языке (CLI, байт-код). Для неуправляемого языка такое сделать практически нереально. Но для CLI — кто мешает? По CLI можно вполне вывести всю информацию о выполнении и о том, что может понадобиться при этом выполнении. Плюс к этому, не помешает сбор статистики выполнения.
Что мы получаем в результате. То, что мы можем производить действия на большим набором объектов в одной команде. Вот и все что я хотел сказать.
Во многом эта разница между декларативным подходом и навигационном напоминает спор между императивными и функциональными языками. То что предлагает функциональный язык, вполне возможно сделать на императивном. Просто больше кода получится.
Здравствуйте, stalcer, Вы писали: S>И еще один хитрый вопрос — должны ли связи быть частью объекта, или же они должны быть отдельными сущностями, возможно (а может и нет) отдельно грузиться, отдельно сохраняться, а самое главное — отдельно объявляться.
Как ты, однако, вопросы-то верно ставишь!
С одной стороны, нутряное чутье подсказывает — если интерфейс объекта публикует связь, то пусть публикует:
public interface ICustomerOrder
{
ICustomer Customer { get;}
}
Как, впрочем, и обратный интерфейс:
public interface ICustomer
{
IEnumerable<IOrder> Orders();
}
В отсутствие ассоциативного доступа ясно, что реализациям этих интерфейсов придется хранить встречные ссылки. Поддержка ассоциативного доступа предлагает выбор между:
public CustomerOrder: ICustomerOrder
{
public ICustomer Customer {
get
{
return Engine.Select("ICustomer customer where customer.Orders.Contains(this)")[0];
}
}
}
и
public Customer: ICustomer
{
public IEnumerable<IOrder> Orders()
{
return Engine.Select("IOrder order where Customer = this");
}
}
Подразумевается, что ответная сторона связи хранит поле соответствующего типа.
С третьей стороны, мы вряд ли сможем предусмотреть все связи на этапе проектирования системы. Особенно если это хорошая, модульная система. И вот у нас есть модуль A (с интерфейсом, скажем, IPerson) и модуль B (c интерфейсом, скажем, IVehicle). Эти модули — от разных производителей, которые знать друг про друга не знают. А мы теперь должны с построить композитную систему, отслеживающую факт принадлежности автомобилей персонам, с минимальным геморроем и максимальным повторным использованием.
У нас есть уже три варианта:
1. Наследуемся от готовой реализации IPerson; расширяем ее интерфейсом
вкупе с соответствующей реализацией хранения списка ссылок на движимое имущество.
2. Обратный вариант — расширяем реализацию IVehicle до IOwnedVehicle: IVehicle, IOwnedObject.
3. Не трогаем реализации вообше. Вместо этого создаем новый хранимый тип
public ClassPersonToVehicleLink
{
public IPerson Person {get; set;}
public IVehicle Vehicle {get; set;}
}
Третий вариант наименее зависим от модулей A и B. Это значит, что потом мы легким движением руки добавим или заменим модуль B модулем B1, где предоставлена альтернативная реализация IVehicle. Таким образом, шансы на повторное использование нашего модуля С резко возрастают.
Вот такая вот петрушка получается. Кстати, третий подход никак не противоречит изобретению интерфейсов IVehicleOwner и IOwnedVehicle и их реализации. Если это где-то будет удобно — нет проблем.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, eao197, Вы писали:
E>Но ведь полиморфизм относится к коду объектов. Так зачем его в RDB складывать?
Дело не в том, чтобы складывать. Дело в том, что мы выполняем запрос
select * from IPerson p where p.Age>27;
Здесь IPerson — интерфейс, Age — виртуальное свойство. Должен вернуться список объектов, реализующих IPerson. C соответствующими значениями Age.
В этом примитивном случае мы, конечно, сможем пойти одним из нескольких путей:
1. Построить view, в котором поле Age возвращается соответствующим способом для каждого класса:
create view IPerson as
select ID, Age from Person1
union
select ID, DateDiff(Year, GetDate(), Birthdate) from Person2
2. Принудительно создать поле Age, которое будет кэшировать значение свойства Age.
Включить в методы, изменяющие состояние объекта, соответствующий код пересчета (в простом случае это поле просто будет в некоторых таблицах вычисляемым)
Увы, в более интересных случаях ничего удобного сделать не удастся. Представь себе портал развлечений. Зададим ему вопрос: на какие события я (зарегистрированный участник) смогу пойти сегодня? В SQL-стиле это будет примерно так:
select * from Events e where e.Accepts(@me) and e.Begins between GetDate() and Tomorrow();
Проблема в том, что каждый потомок класса Event определяет свои правила контроля посетителей. В каком-то классе Accepts всегда вернет true, в каких-то — проверит возраст, и так далее. Это и есть полиморфизм.
Решить эту проблему не так уж сложно. Для каждой конкретной объектной модели мы сможем построить конечный код:
create procedure GetAcceptableEvents (@me Person)
as
select ID from MovieSessions ms
inner join Movie m on ms.Movie = m.ID
inner join MovieCategory с on m.Category = c.ID
where c.MinAge<=@me.Age
and ms.StartTime between GetDate() and Tomorrow()
union
select ID from PeepShow ps where @me.Gender = MALE and @me.Age>=21
aand ps.StartTime between GetDate() and Tomorrow()
union
...
Я намеренно упростил определение — этот код хоть и похож на T-SQL, не станет работать как минимум до MS SQL 2005. SQL 2000 — совместимый код будет посложнее, т.к. придется передавать все компоненты Person по отдельности.
Но уже здесь виден основной косяк: при добавлении в систему очередного типа развлечения, эту процедуру придется переписывать. А все потому, что мы были вынуждены "складывать полиморфизм в RDB". Иначе мы не могли эффективно получать результат нашего запроса. Нет, конечно, мы могли выполнить фильтрацию по хранимым атрибутам на стороне RDB, а уже потом выполнить остальную часть предиката на уровне сервера приложений. Но это немногим лучше — с точки зрения эффективности, мы игнорируем часть потенциально полезных индексов, а с точки зрения производительности труда должны учитывать все эти подробности еще на уровне проектирования, а не реализации, делая рутинную работу вручную.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, eao197, Вы писали:
E>Нет, это проблема, только если выбранная коллекция требует для своего изменения полной загрузки себя в память. Например, если коллекция -- это вектор (непрерывная последовательность ссылок). А если коллекция -- это дерево, то в память нужно будет загрузить только вершину и те промежуточные узлы, которые ведут к модифицируемому узлу. И если речь идет о B+ дереве, например, то изятие одного элемента из дерева в несколько миллионов элементов потребует доступа всего к нескольким узлам (страницам) дерева.
Я о чем и говорю: коллекции в таком случае должны быть построены так, чтобы не нужно было подгружать ее вообще. Может быть даже просто запоминать все изменения в какой-то другой структуре, для того чтобы когда коллекция реально потребуется — загрузить ее (коллекцию) и скорректировать.
Тут еще фишка в том, что в большинстве случаев коллекции — маленькие и без разницы грузить ее всю или только часть. Это все равно одно обращение к базе. А вот если совсем не грузить , это да, это хорошо.
А еще может быть и обратная ситуация. Когда коллекция уже загружена, и из нее, например, удаляем объект. Или еще круче: делаем просто Clear(). И прикинь, что для этого необходимо будет подгрузить все соответствующие children объекты, чтобы изменить в них ссылки.
А ведь и та и другая ситуация может быть с равной вероятностью. И придумать алгоритм, который бы не грузил лишнее в обоих случаях — вот хитрая задачка.
Джентельмены, с удовольствием прочел ваши мнения, позвольте высказать свое.
Сервера приложений (как и многое в нашей жизни) делятся на две категории:
1. Бизнес-объекты полностью инкапсулированы и полиморфно работают только сами в себе.
2. Бизнес-объекты прокачиваются через набор сервисов, и те делают с ними те вещи которые называются бизнес-логикой.
"Правильный" сервер-приложений, по-моему мнению, это оба этих подхода в одном флаконе. И таким образом — в зависимости от требований, при построении бизнес-логики обуславливает крен в ту или иную сторону.
Что такое "чистая" ООБД в моем понимании. Это некоторая БД оперирующая объектами и реализующая, по крайней мере, пункт 1. То есть, ни одна сволочь не может добраться до состояния объектов минуя реализацию бизнес-объекта. В том числе и декларативный запрос. Запросы — это не столько получение некоторого набора объектов, а еще инструмент выполнения некоторых действий на некоторым множеством объектов. По этому поводу, еще хочется сказать. К сожалению, в текущих версиях ООДБ основным считают навигационный доступ, а запросы — некоторая дополнительная сущность. Мне это не нравится.
Насколько она должна держать п2 — не знаю. Но отрицать что бизнес-объект может быть максимально прост и оперироваться сервисами, нельзя. Это решение задачи предложенной eoa197.
[to eao197]
Что касает предложенной тобой заморочки с изменяемыми реализациями. Иногда ее сильно нехватает. С ней, можно было-бы сократить паттерны GoF. Но это палка о двух концах. При этом нужно учитывать, что она не только содержит в себе все недостатки множественного наследования, но и усугубляет их. Если ты попробуешь формализовать процесс создания нового объекта, то ты получишь нехилую кучу требований которые трудно будет выполнять. Если сейчас спросить 10 программистов С++, в каком порядке выполняются конструкторы в объекте с множественным наследованием, то дай бог хоть один уверенно ответит (хотя тут догадаться несложно). Недаром в последних языках используются именно объекты с множественным наследованием интерфейсов без реализаций. Если bvb пользоваться + дополнительно сервисы — то проблемы сами разрешаться.
. А именно — практическая невозможность построить эффективный механизм запросов не имея полного контроля хранилища.
Что касается перегрузки на клиента — то на это наплевать. Кэширование на клиенте, так на клиенте. Если при этом выполняется п1, то на здоровье. Такой механизм все-таки возможен (правда по первым прикидкам наверное не эффективен).
Что касается билетов. Была некоторая рекламная статья, от какой-то OODB. Какая не помню (давно было), но прикольно то что они как раз и обналичивали кассы авиабилетов. Вобщем замена Oracle на OODB дало очень большой прирост в производительности. Но чего-то сразу ее не нашел. Так что, верьте на слово.
С уважением, Gleb.
PS: IMХО Не советую пользовать C++/CLI. Только для системных вещей требующих unmanaged код, которых не так уж много. Но это вопрос другого флейма.
Джентельмены, давайте я примерно обрисую как я вижу применение OQL.
Итак. Опишем примерно стандартный сервер приложений
Стандартный сервер приложений состоит как минимум из трех слоев.
1. Фасад. То с чем общается клиент.
2. Бизнес-логика. Набор объектов и серверов.
3. Хранилище объектов. Сама БД.
Слой типа DACL я не буду упоминать, так как они в принципе к разговору не имеют отношения и реализуется любой ORM или ООБД системой. Остальные тоже поскольку не имеют отношения к разговору.
Начнем с самого верха, с фасада. У него много названий, иногда называется Remoting Facade. Одна из проблем, даже сказал бы наиболее существенная проблема решаемая им, гранулярность вызова. То есть, при вызове сервера приложений клиент старается одним вызовом сделать максимум нужной работы. Для используются два пути: 1 путь — добавление максимального кол-ва параметров в функцию вызова, 2 путь — pattern комманд. При реализации паттерна command обычно используется OQL подобный язык запросов. Так в чем-же дело?
Второе уровень. Бизнес-логика. Бизнес-логика — это набор классов отвечающих за функционирование самой логики бизнес приложений. Его можно построить используя навигационный доступ(что и делается в большинстве систем). В данном случае — OQL также имеет некоторый смысл. Коли у нас есть элементарные команды приходящие из фасадного уровня, многие команды могут быть собраны из этих элементарных команд.
Для третьего уровня OQL не нужен. Он вообще не должен быть виден прикладному программисту. Чем меньше программист знает о физическом уровне хранения, тем лучше спят остальные. Это уже чистая пререгатива логики БД. Однако — из чего состоит эта логика. Исполнение OQL зависит от этого уровня. Чем выше будет hit ratio выполнения OQL команды, тем эффективнее будет сервер. Тут нужна предсказательная логика основанная на статистике выполнения функций бизнес-логики. И чем более глубоко можно будет залезть в эту логику, тем быстрее будет выполнен запрос. Это и есть самая большая сложность. Но плюсы по сравнению с теперешними системами — будут огромны.
Итого, при нормальной реализации языка, можно вполне говорить о том, что ООБД — уже готовый сервер приложений.
eao197 пишет:
> Значит возможностей РСУБД в этом направлении с лихвой хватает. И > совсем не факт, что супер-пупер ООСУБД (если такое вообще возможно) > сделает прорыв в этой области. А Java я упоминул, потому, что там, как > мне помниться, в J2EE были работы по прозрачной сериализации > Java-объектов в БД и по такому же прозрачному подъему из БД.
Тут разве еще не говорили? http://www.hibernate.org/ — OR-mapping для
Java. Поддерживает отображение отношений, _полиморфзм_ (он замечательно
ложится на РСУБД, кстати) и еще кучу фич.
И что характерно — все работает и реально используется.
E>>По отношению к ООСУБД более интересно другое: должны ли эти алгоритмы быть частью ООСУБД или ООСУБД должна предоставлять средства для их эффективной реализации на прикладном уровне?
S>Если само понятие двунаправленных связей — определено в ООСУБД, то да, должны быть частью ООСУБД. По моему, двунаправленные связи совсем не лишние в ООСУБД. Наоборот, очень естественно иметь объекты и связи между ними. И к UML ближе. Ссылочные аттрибуты, в каком-то смысле, более надуманное понятие.
ООСУБД не должна содержать такие алгоритмы, так как учет всех таких ситуаций (и способов их решения) приведет к разрастанию такой СУБД до махины, в которой ни Вы, ни я, ни кто-либо вообще не разберется. Так что мне кажется достаточно (более чем) просто предоставить инструменты создания таких алгоритмов. Например, Versant VDS поддерживает B+ (т.е когда для коллекции можно указать, что ее надо хранить в B+) — вот пример наличия инструментов (предоставляемых) для реализации алгоритмов оптимизации хранения.
Здравствуйте, GlebZ, Вы писали:
GZ>Запросы — это не столько получение некоторого набора объектов, а еще инструмент выполнения некоторых действий на некоторым множеством объектов. По этому поводу, еще хочется сказать. К сожалению, в текущих версиях ООДБ основным считают навигационный доступ, а запросы — некоторая дополнительная сущность. Мне это не нравится.
Думаю вполне уместным будет выложить здесь мое мнение относительно языков запросов и ООСУБД.
Из личной практики работы с продуктами Versant я вынес следующее. Запросы нужно использовать при работе с ООСУБД как можно реже. Причин тут несколько.
Во-первых, чувствуется слабость оптимизаторов (особенно это касается FastObjects). Как результат приходтся более внимательно писать приложение и часть работы по оптимизации выполнять самому, не надеясь на то, что оптимизатор выберет наилучшее решение. Но главное — нужно так строить сами объектные структуры, чтобы заменить запросы прямой навигацией. Ко всему и ограниченность имеющегося языка запросов (FastObjects) не способствует тому, чтобы было желание запросы активно использовать. Как ни странно, указанный подход вполне срабатывает. ООСУБД предлагают достаточно инструментов, которые реально замещают запросы во многих ситуациях.
Во-вторых, сложна судьба самого языка запросов ООСУБД. Существует спецификация ODMG, которая определяет язык запросов OQL. Именно на базе OQL и строятся сегодня языки запросов разных СУБД. Но основная беда OQL в том, что в период его создания у разработчиков было немерянное желание сделать его максимально похожимна SQL, что и породило массу проблем и вопросов (ака "что вернет запрос ... ?"). Производители ООСУБД, тем не менее, вынуждены поддерживать то, что включено в спецификацию и развивать эту поддержку. Но логика развития демонстрирует странные факты. OQL, существующий уже давно, не вызывает особых симпатий, а разработчики, например на Java, предпочитают более адаптированный к их нуждам JDOQL.
По моим личным впечатлениям декларативные языки запросов вообще не подходят для работы с ООСУБД — они не соответствуют объектной парадигме этих систем, вступая с ней в противоречие. Более понятным и продуктивным здесь может быть процедурный/функциональный подход к написанию запросов.
И, кстати, производители ООСУБД этот подход поддерживают, хотя пока и нельзя сказать, что он сильно развит (далее все гипотетически, конкретных продуктов, работающих подобным образом я не знаю). Т.е. вместо OQL запроса вида: "SELECT * From ObjectClass Where ObjectClass.atrrib = const_Object" мы в ОО-программе пишем что-то вроде "database.GetCollecttion('ObjectClass', constObject.equals)" и получаем результат-коллекцию. Обычно это коллекция ссылок на объекты.
Но уже и в этом примере видно, что включение объекта Object в результирующую коллекцию происходит в зависимости от того, какой результат возвратит метод cons_Object.equals(Object). Как оптимизировать такие запросы, если код метода equals может быть очень сложным? Где отрабатывать код метода? Пока что ответов на эти вопросы нет. Но похоже производители движутся именно в этом направлении (и в первую очередь об этом свидетельствует рост популярности функциональных языков запросов: JDOQL, XQuery, WebOQL ... ). Т.е. методы отрабатываются на сервере приложений, а база данных только предоставляет данные для сервера приложений, помогая ему чем может (индексы, транзакции ... ).
Чтобы создать систему, действительно способную оптимизировать такие запросы, разработчикам ООСУБД еще предстоит много и много потрудиться (адаптивные методы оптимизации еще не вышли научных институтов), но формально реализовывать системы, в которых подобные механизмы будут работать, сегодня уже никто не мешает. Весь инструментарий доступен и в целом вполне удобен при использовании (базируется на использовании итераторов, пространств классов и т.п.). Просто вопросы оптимизации, увы, пока лежат на разработчиках подобных систем.
Ты хочешь сказать, что описав алгоритм Accepts методов в каждом из классов при помощи императивного языка, ты потом сможешь соптимизировать запрос, типа:
select * from Events e where e.Accepts(@me)
чтобы у него была производительность лучше чем O(n). Причем как ты сам же утверждаешь — для нетривиальных случаев, то есть для сложного алгоритма в Accepts.
Ню ню. Флаг тебе в руки и т.д.
ИМХО, ты этого сделать не сможешь. И это даже не вопрос построения СУБД, это вообще вопрос оптимизации императивных языков программирования, которой на практике — нет и не предвидится, хотя компиляторов понаделано — море. И ни один из них даже инлайнить виртуальные функции не умеет. Потому что — это бред, если подумать.
Вот такая вот постановка вопроса! Если ты не можешь этого сделать, то вся декларируемая тобой поддержка полиморфизма — ничего не стоит.
Сейчас и обычные РСУБД умеют выполнять хранимые процедуры в запросах. Ну и что. Это только дополнительная красивая фича.
Так как главная задача базы — хранить данные. И только из этой задачи возникает необходимость в языке запросов, как в средстве доступа к хранимым данным. А процедура — это не данные. И поэтому возможность выполнения процедур в языке запросов не сильно нужна.
Это вторая точка зрения.
И еще одна точка зрения на процедуры в запросах:
Практически, самой главной фичей в запросах стала возможность их оптимизации. Если бы не было возможности оптимизации — то весь SQL представлял бы из себя только средство описать условия выборки несколько короче, чем на императивном языке.
Именно исходя из возможности оптимизации синтаксис и семантика SQL и были разработаны. Именно поэтому выполнение хранимых процедур в SQL (даже без полиморфизма) — есть зло.
То есть SQL, как язык специально подталкивает пользователя писать таким образом, чтобы была хоть какая-то практически значимая вероятность оптимизации. Пусть и ценой некоторых неудобств, о которых вы тут все кричите.
Ну и в заключении повторюсь, что ИМХО, ты не сможешь сделать оптимизатор запросов с использованием императивного языка для описания методов объектов, чтобы достичь практически значимой вероятности оптимизации запросов. Это даже не говоря о полиморфизме.
А без этого все твои идеи ничего оригинального не представляют, так как все это уже есть, например, в Oracle 9i. И тормозит там все так, как и логично было бы предположить.
Ну и на самый последок: Все эти проблемы давно известны. И единственный выход, который я вижу — это некий компромисс: разделение СУБД и сервера приложений, и как следствие уменьшение требований к СУБД. И может быть, усложнение написания программ с точки зрения прикладного программиста, чтобы добиться возможности оптимизации запросов.
И в этом свете действительно разница между РСУБД и ООСУБД небольшая.
Так что решение здесь должно быть чисто организационное, на более высоком уровне абстракции, с точки зрения всей системы в целом, а не только СУБД.
Еще один путь — снизить требования к ООСУБД. Например, сделать как в Delphi. Там в формах сохраняются свойства, а не поля. То есть, некоторая инкапсуляция есть. Вот и сделать так, чтобы сохранялись свойства, и в языке запросов оперировать свойствами. Это по моему вполне реальный путь.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, vdimas, Вы писали:
V>>Блин, похоже все потеряли нить разговора. Речь-то идет о хранении данных в ОП. (о подобной гипотетической возможности). Дык, если все хранится в памяти произвольного доступа, то как суррогатный ключ мне поможет уменьшить кооличество задействованных объектов??? Вместо foreighkey вообще просто коллекция объектов на стороне master и ссылка на мастер на стороне detail (для one-to-many). Куда уж быстрее, если у меня и так все данные правильно сгруппированы и мне искать и выбирать ничего не надо, все уже выбрано и найдено. GZ>Тут ты задвинул две проблемы. Допустим у нас есть нев.. ну в общем очень большой справочник операций сделанных над документами. Операций делаются по несколько тысяч за день. Можем ли мы сохранить ссылки на операции из документов? Нет не можем. Иначе у нас получится что связи (массив OID или указателей, как тебе будет угодно) намного больше чем сам документ. То есть, проблема избыточности связей существует (что в реляционке решается нормализацией). При этом есть такая шняга, что если документ убили, операции о нем не должны исчезнуть. GZ>Вторая проблема которую ты решил не видеть. Нам нужно найти операции просмотра с определенным документом. Ну и что тут делать? Просматривать все операции? Не лучше ли поднять индекс и сделать это весело и быстро, чем тормозить и грустно
Имхо, такие проблемы лечатся, если поднятие объекта из БД не означает автоматического поднятия всех объектов по его ссылкам. Тогда, для приведенного примера, в объекте-документе может быть ссылка на объект-историю. А уже в истории будет храниться список модификаций (тем или иным образом организованный). Если объект-документ извлекается из БД без объекта-истории, то нет проблем с производительностью.
Такой подход был в свое время реализован в POET -- там при загрузке объекта можно было указывать, что делать с объектами по ссылкам: либо грузить все, либо грузить определенные типы ссылок. А в Goods, если мне не изменяет память, ссылки между объектами реализовывались на основе "умных указателей". И реальный доступ к объекту через умный указатель осуществлялся только тогда, когда было обращение по этому указателю.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, BaZa, Вы писали:
BZ>>ООСУБД не должна содержать такие алгоритмы, так как учет всех таких ситуаций (и способов их решения) приведет к разрастанию такой СУБД до махины, в которой ни Вы, ни я, ни кто-либо вообще не разберется. Так что мне кажется достаточно (более чем) просто предоставить инструменты создания таких алгоритмов. Например, Versant VDS поддерживает B+ (т.е когда для коллекции можно указать, что ее надо хранить в B+) — вот пример наличия инструментов (предоставляемых) для реализации алгоритмов оптимизации хранения.
S>Нет уж, простите. Речь же шла о кэшировании связей. Этим СУБД очень как должна заниматься. Или вы предлагаете вообще отказаться от двунаправленных связей — как понятия? И переложить их организацию на плечи прикладного программиста? А СУБД будет только поддерживать ссылки и коллекции (ссылок)?
S>Так что если понятие двунаправленных связей вкладывать в ООСУБД, то все эти алгоритмы должны присутствовать. ИМХО ничего не будет разрастаться, просто вдобавок к одному базовому понятию — объект (класс), будет еще и другое — связь (ассоциация). И я специально подчеркнул, что даже UML на это пошел. Так что не вижу здесь ничего страшного. А полезного — вижу много.
Связи не имеют имени. Вместо этого именуются навигационные пути (traversal paths) для каждого направления навигации, например профессор преподает (teaches) совокупность разделов курсов, инверсное направление определяется тем, что разделы курсов преподаются (is_taught_by) профессорами. Эти имена объявляются в определениях интерфейсов, соответствующих типам, участвующим в связи:
interface Professor { ...
teaches: Set<Section> inverse Section::is_taught_by
}
и
interface Section { ... is_taught_by: Professor inverse Professor::teaches
}
Для типа связи 1-n определены следующие операции:
— create(o1:Denotable_Object, s:Set<Denotable_Object>);
— delete ();
— add_one_to_one (o1:Denotable_Object, o2:Denotable_Object);
— remove_one_to_one (o1:Denotable_Object, o2:Denotable_Object);
— traverse (from:Denotable_Object) -> s: Set<Denotable_Object>.
При этом, как я себе это предствлял, изменение множества Professor::teaches автоматически приведет к модификации соответствующих Section::is_taught_by.
Но здесь в дело вступает другой момент: насколько эффективной должна быть реализация Set<...> inverse на уровне ООСУБД? Ведь могут быть разные случаи: когда множество маленькое и его лучше представлять в виде вектра или, наоборот, множество может быть очень большим (как в случае с обсуждаемым нами примером документа и истории его изменений). Кто должен выбирать, как Set<...> должна быть реализовано?
Я понял BaZa так, что если пойти на реализацию на уровне ООСУБД различный вариантов контейнеров связей (SmallSet, BTreeSet, HugeSet, SmallList, HugeList, ...), то такая ООСУБД действительно будет вынуждена поддерживать массу функциональности. Например, на уровне поддержки эволюции схемы данных нужно будет поддержать преобразование атрибута Professor::teaches из SmallSet в BTreeSet и обратно.
Может быть более выгодным способом будет предоставление одного типа связи dual_ref? А все остальное делать на основе этой связи и стандартных или нестандартных контейнеров? Например:
Сейчас подумалось, что ООСУБД по выражению dual_ref< Professor::teaches > трудно будет понять, что в контейнере Set находятся ссылки. Ведь если нет специального типа "множество ссылок", а есть только контейнеры, то могут быть контейнеры контейнеров и др. И как во всем этом нужные ссылки искать? М-да...
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, stalcer, Вы писали:
S>Неа. Я не про это вовсе. Здесь же речь идет о кэшировании объектов базы данных. Вот это "возможно большое количество объектов" может быть вообще не подгружено в кэш. И что тогда делать? Тупой вариант — это подгрузить их все, изменить в каждом поле, и сохранить эти изменения обратно на диск. Но, это плохой вариант.
А почему бы просто не подождать до тех пор, пока они не подгрузятся в кэш по какой-либо иной надобности? А пока просто оставить специальную метку на месте удаленного объекта. Т.е. ссылки редактировать не сразу, а только по мере обращения к соответствующим объектам?
Здравствуйте, stalcer, Вы писали:
S>Неа. Опять непонятки по теме разговора.
Я немного просто расскажу как это сделано в Versant Developer Suite.
Есть специальный тип BiLink — двунаправленная ссылка. Вот некоторые выдержки из описания.
BiLink and BiLink Vstr Usage
Bi-directional links and bi-directional link vstrs allow creation of links and back links among objects using a single attribute in each of the linked objects. The C++/VERSANT classes that can hold a bi-directional link are:
BiLink<type>
Typed storage of a bi-directional link to another object.
BiLinkVstr<type>
Typed variable length storage of multiple bi-directional links to other objects.
BiLinks — BiLinks are bidirectional forms of the link classes that create bidirectional links between objects that derive from PObject. Like links, bilinks establish object relationships using logical object identifiers stored in a single attribute in each of the linked objects.
BiLinks are defined in the BiLink<type> class. The type parameter specifies the type of the target object. To specify the nature of the back link, you must add a "relationship" statement to the class implementation file. See the section "Creating BiLink and BiLink Vstr Classes" for more information.
BiLink Vstrs — BiLink vstrs are bidirectional forms of the link vstr classes that store multiple bidirectional links between objects that derive from PObject. Like link vstrs, bilink vstrs establish object relationships using logical object identifiers stored in a single attribute in each of the linked objects.
BiLink vstrs are defined in the BiLinkVstr<type> class. The type parameter specifies the type of the target object. To specify the nature of the back link, you must add a "relationship" statement to the class implementation file.
By using bilinks and bilink vstrs, you can create any form of bidirectional relationship among objects. For one-to-one relationships, use bilinks as an attribute in both objects. For one-to-many relationships, use a bilink as an attribute in one object and a bilink vstr as an attribute in the other object. For many-to-many relationships, use bilink vstrs as attribute in both objects.
Following are bilink and bilink vstr usage notes.
• To use bi-directional link and bi-directional link vstr classes, include pobject.h and bilink.h.
• BiLink and bilink vstr attributes should be a public database member of a persistent class.
• BiLink targets must be derived from PObject. Targets of links must derive from PObject. This is because bilinks use the unique logical object identifier that is present only in objects deriving from PObject.
• If a bilink or bilink vstr will point to heterogeneous types, you must supply a type parameter of a base class of all the types involved and cast results downwards as appropriate with the AS() or L_AS() macro.
• Logical object identifiers are not assigned until constructors are finished. This means that it is dangerous to set bilink or bilink vstr attributes in a constructor.
• Whenever you need to use double right angle brackets, such as when a template is used as a type parameter, follow coding guidelines for your compiler. This may mean that you must insert a space between double right angle brackets to avoid them being taken as the right shift operator.
• Virtual methods must be added or redefined indirectly. You cannot directly create or redefine virtual methods in bilink and bilink vstr classes, but you can embed a bilink class, add virtual methods to the class, and then embed the new class in another persistent class.
• BiLink vstrs handle their own memory allocation. Memory used by a bilink vstr is released in the destructor. Thus, there is no release method to handle memory allocation. If a bilink vstr is empty at the time of a commit, then it is automatically deleted.
• BiLink vstrs should not be compared to NULL. Instead bilink vstrs should be tested for being empty by using the is_empty() or size() methods.
• The size of a bilink vstr is part of the persistent state of a bilink vstr object. The size of a bilink vstr is the number of elements that will be saved to or retrieved from a database. The initial size of a bilink vstr is always zero and is changed by adding elements with add() or resizing with set_size().
• If a bi-directional link or bi-directional link vstr contains versioned objects, all objects on each side of the bi-links must be checked out together.
• Two persistent objects may not share the same bilink vstr.
• Setting a forward bilink will automatically set a back link. If you change a bilink from one object to another, existing bilinks will be adjusted. • If you change a bi-directional link from one object to another, existing bilinks will be adjusted.
• Deleting an object in a bilink or bilink vstr will cause bilinks pointing to that object to be set to null. However, since bilinks provide by-reference semantics, deleting one object in a bilink relationship will not delete the other object. If you want, you can add behavior to your own classes to propagate deletions.
• In general, we recommend that objects that have bilinks or bilink vstrs as attribute types, should not be versioned, because the bi-directional relationship may become inconsistent when updates are made to the bilink or bilink vstr attributes.
Creating BiLink and BiLink Vstr Classes
To create and use the bilink classes BiLink<type> and BiLinkVstr<type>, where type is the class of the target objects, do the following.
1. Include files.
Include both the PObject and BiLink class files in an appropriate class specification file:
2. Forward declare the class used in the bilink or bilink vstr.
In a class declaration file .h, declare the type of the objects to be used in the BiLink<type> or BiLinkVstr<type> class.
3. Declare bilink and bilink vstr attributes to be public.
Declare the attributes that will contain the bilink and bilink vstr relationship to be public.
4. Specify the type of relationship.
Specify in a class declaration file .h and implement in a class implementation file .cxx the nature of the bilink relationship: one-to-one, one-to-many, many-to-one, or many-to-many. This is done by using the add() function. Each of the possible ways of using add() returns an integer. If the association succeeds, the return value is 0.
A convenient place to calling an add() function is at the initialization of a static dummy variable.
One BiLink to One BiLink
To establish a one bilink to one bilink relation between class A and class B:
BiLink_to_BiLink<A,B>::add(&A::toB,&B::toA);
One BiLink Vstr to Many BiLinks
To establish a one bilink vstr to many bilinks relation between class A and class B:
BiLinkVstr_to_BiLink<A,B>::add(&A::B_Vstr,&B::toA);
Many BiLinks to One BiLink Vstr
To establish a many bilinks to one bilink vstr relation between class A and class B:
BiLink_to_BiLinkVstr<A,B>::add(&A::toB,&B::A_Vstr);
Many BiLink Vstrs to Many BiLink Vstrs
To establish a many bilink vstrs to many bilink vstrs relation between class A and class B:
BiLinkVstr_to_BiLinkVstr<A,B>::add(&A::B_Vstr,&B::A_Vstr);
The add() function establishes bilink relations at run-time.
For each bilink relation, at least one of the the above template functions should be called before any use of the bilink relation.
For example, to define bilinks and their relations, first define the bilinks:
class B; // mandatory forward declarationclass A: public PObject {
public:
BiLink<B> toB; // attribute must be public
BiLinkVstr<B> B_Vstr; // attribute must be public
...
};
class B: public PObject {
public:
BiLink<A> toA; // attribute must be public
BiLinkVstr<A> A_Vstr; // attribute must be public
...
};
Next, add an association initialization statement for each relation to one of the application's .cxx
files.
For this example, a one-to-one link connects toB with toA, and a many-to-many link connects B_Vstr to A_Vstr. You can call the add() function in the initialization of static dummy variables:
static int dummy1 =
BiLink_to_BiLink<A,B>::add(&A::toB,&B::toA);
static int dummy2 =
BiLinkVstr_to_BiLinkVstr<A,B>::add(&A::B_Vstr,&B::A_Vstr);
...
Таким образом в VDS двунаправленные ссылки фактически являются отдельными объектами, которые имеют структуру списка в случае one-to-many ссылок. А сами объекты с атрибутами-двунаправленными ссылками фактически содержат ссылки на объекты BiLink или на конкретные элементы списка внутри объекта BiLink. Удаление и редактирование основных объектов-контейнеров приводит к поднятию соответствующего объекта BiLink и проведению с ним неких манипуляций. Но при этом второй (множество) связанный с ним по двунаправленной ссылке объект не затрагивается — изменяются только объекты BiLink.
Здравствуйте, eao197, Вы писали:
E>Я когда-то делал два типа ссылок: soft_ref и hard_ref. Объясню на примерах. Пусть объект A ссылается на объект B с помощью seft_ref, а объект C ссылается на объект D с помощью hard_ref. Объекты B и D не могут быть удалены, пока существуют объекты A и C. Если же удаляется объект A, то объект B остается в базе, просто для него уменьшается счетчик ссылок. Если же удаляется объект C, то с ним вместе удаляется и объект D (при условии, что на него кроме A больше никто не ссылается). Т.е. hard_ref -- это отношение владения (D без С не может существовать), а soft_ref -- это соседские отношения.
Фактически, это третий тип ссылок. Трабл с ним я вижу в том, что не вполне понятно, что произойдет в случае наличия еще и soft_ref ссылок на объект D. Понятно, что само наличие двух hard_ref ссылок на один объект в такой системе — косяк. А вот что делать с софт ссылками — непонятно.
Мы в свое время делали сборку мусора на основе подсчета ссылок. В ней удаление объекта взводило флаг "удален", после чего создание новых ссылок на него было запрещено, и уменьшало счетчик на единичку. Для нового объекта количество ссылок ставилось в единичку. При достижении нулевого количества ссылок объект удалялся из БД.
С философской точки зрения, это эквивалентно внесению в традиционную технологию refcount концепции "внешнего наблюдателя". При создании объекта внешний наблюдатель как бы говорит: "я за тобой слежу". Выполняя удаление объекта, наблюдатель говорит "я перестал за тобой следить". Естественно, основная проблема концепции refcount — повисание циклов — сохранялась. Я пока что забил на вопросы управления временем жизни объектов в ООСУБД, хотя практика управляемых сред показывает рулезность GC и недетерминистической финализации по сравнению со всем остальным. Так что с моей точки зрения, самой "правильной" реализацией должна быть именно поддержка автоматического GC на основе достижимости объектов, модифицированная присутствием "внешнего наблюдателя". Эта модификация необходима, чтобы свежесозданные объекты не умирали самопроизвольно, продолжая оставаться доступными при помощи ассоциативного доступа. Хотя, с учетом наблюдения, сделанного сталкером
, внешнего наблюдателя можно и не вводить. Т.е. помечая объект как доступный для поиска при помощи включения его в коллекцию, мы гарантируем его выживание благодаря наличию ссылки.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, eao197, Вы писали:
S>>Одно из требований (желаний) я определил: Надо сделать так, чтобы при изменении одного конца связи не нужно было грузить всю коллекцию (или объект со ссылкой) на другом конце.
E>Но тогда нужно определить еще и условия, при которых этого не нужно делать. Ведь если все коллекции ссылок будут обрабатываться таким образом независимо от их размера, то накладные расходы на хранение этих коллекций могут оказаться слишком высокими.
В базах данных, в этом смысле, есть один очень положительный момент: основное время тратиться на работу с диском. Это само по себе, конечно очень плохо, но зато можно не экономить на работе в кэше. То есть формат данных в кэше можно сделать и более навороченным, по сравнению, например, со стандартными коллекциями C++.
В данном конкретном случае — всегда нужно стремиться к тому, чтобы не загружать зря коллекцию с другой стороны. Так как накладные расходы на загрузку будут несоизмеримо больше, чем работа с кэшем.
Здравствуйте, stalcer, Вы писали:
S>И еще один хитрый вопрос — должны ли связи быть частью объекта, или же они должны быть отдельными сущностями, возможно (а может и нет) отдельно грузиться, отдельно сохраняться, а самое главное — отдельно объявляться.
Кстати, в текущем проекте мы пришли именно к тому, что все связи — это беззаговорочно отдельные сущности. Если в некоем объекте есть колллекция других подчиненных объектов, то это реализовано как свойство-фасад (типа ICollection), делегирующее функциональность к выделенной сущности-линку.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, BaZa, Вы писали: BZ>>Мне просто, например, интересно, так ли необходимо хранение методов в ООСУБД (как в Gemstone и O2)? S>Ну, вообще-то, лично я бы постеснялся назвать базу без хранения методов объектно-ориентированной. Поскольку из пяти концепций объектно-ориентированного программирования поддерживаются только две: идентифицируемость и наследование. О поведении, вместе с инкапсуляцией и полиморфизмом, можно забыть. Не вполне очевидно, нужно ли вообще наследование без полиморфизма.
А я бы нет
Ведь база данных -- это хранилище данных. Для чего там код?
Чтобы исполнятся во время выполнения запросов на серверной стороне, например.
Ok. Здесь это было бы полезно. Может быть. А может быть было бы достаточно в языке запросов простых примитивов сравнения.
Например, если БД содержит огромное количество структурированной измерительной информации (Objectivity в CERN, как мне помниться, как раз для этого и применялась), то большинство объектов в ней вообще не нуждаются в методах. Или БД, которые содержат чертежи из CAD систем. Большинство объектиков в них будут какими-нибудь точками, многоугольниками, ломанными и окружностями. Для которых поддержка методов в БД так же может быть избыточной. Для таких БД вообще поддерживать методы не имеет смысла. Но вот объектную-ориентированность они поддерживать должны -- извлеченный из БД объект должен становиться точно таким же объектом в программе, которым он был до записи в БД.
Или для того, чтобы закачиваться на сторону клиента вместе с объектом. То же может быть. На примере Java-апплетов что-то подобное уже изобреталось.
Только может быть и другая точка зрения. У каждого клиента может быть свой интерфейс к данным. Т.е. фактически, объект SomeObject, который лежит в БД может при загрузке в одного клиента иметь совсем другой интерфейс, чем при загрузке в другого клиента. Например, класс Point для чертежа CAD системы может иметь несколько реализаций (но одно представление данных) -- одна реализация для использования в редакторе чертежей, одна реализация для использования в программе печати чертежей, одна реализация для программы подсчета количества требуемых для реализации нарисованной на чертеже детали материалов и т.д. В таких условиях в централизованном хранении методов классов на сервере нет смысла.
Так же, если класс объекта в БД может иметь различные реализации в коде клиентов, не понятно, какую из реализаций какого-то метода объекта использовать при выполнении запроса. Запрос от редактора чертежей -- это одно. А запрос от программы печати чертежа -- это уже совсем другое.
Если речь идет о неуправляемых языках, таких как ObjectPascal или C++, то хранение методов объектов в БД -- это что вообще? Наличие dll-ки рядом с БД и ее ручная подгрузка сервером БД с реализацией обращений к функциям из этой dll?
В некоторых случаях создание таких dll будет настолько трудоемкой задачей, что клиенты БД просто не будут этой возможностью пользоваться.
В моем понимании ООБД -- это прежде всего поддержка понятия наследования по отношению к хранящимся в ней данным. Инкапсуляция и полиморфизм -- это уже поведение, а не данные. А поведение определяется программой, которая данные использует. Но никак не данными.
Хотя ООБД настолько размытое понятие, что каждый волен не только понимать под этим термином все, что угодно. Но и реализовывать ООБД по собственному вкусу и цвету. И, что интересно, находить области применения для реализованных в БД возможностей.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали: E>Ведь база данных -- это хранилище данных. Для чего там код?
Занятный поинт E> E>Чтобы исполнятся во время выполнения запросов на серверной стороне, например. E>Ok. Здесь это было бы полезно. Может быть. А может быть было бы достаточно в языке запросов простых примитивов сравнения.
Гм. Простые примитивы сравнения уже есть. В RDBMS. Почему-то оказывается, что их не хватает. Если хватает, то зачем какие-то ОО в названии? E>Например, если БД содержит огромное количество структурированной измерительной информации (Objectivity в CERN, как мне помниться, как раз для этого и применялась), то большинство объектов в ней вообще не нуждаются в методах.
Как, впрочем, и в объектах. Я плохо знаком с тем, что хранит CERN. Подозреваю, что у них с теми объектами, которые мы привыкли видеть в ООП, общего мало или вообще ничего.
Кстати, я встречал такое мнение, что ООБД — это "способ придания семантики данным типа BLOB". E>Или БД, которые содержат чертежи из CAD систем. Большинство объектиков в них будут какими-нибудь точками, многоугольниками, ломанными и окружностями.
Пардон за оффтоп, но можно мне вообще объяснить, зачем чертежи CAD систем хранить в БД? Почему не использовать более традиционное хранилище? Я еще понимаю GIS-системы: там есть и многопользовательская работа с едиными данными, и нетривиальные запросы (которые имеет смысл исполнять в клиент-серверной архитектуре). А в CAD-то зачем? Чертеж есть вроде как неделимая сущность... Там вообще на серверной стороне даже структуры вроде не надо. E>Для которых поддержка методов в БД так же может быть избыточной. Для таких БД вообще поддерживать методы не имеет смысла. Но вот объектную-ориентированность они поддерживать должны -- извлеченный из БД объект должен становиться точно таким же объектом в программе, которым он был до записи в БД.
Это не имеет никакого отношения к объектной ориентированности. Точнее, объектная ориентированность здесь не имеет отношения к базе данных. Если подходить с такой мерой, то окажется, что даже dBase поддерживает объектную-ориентированность, поскольку объект, записанный в БД, становится точно таким же объектом при чтении. Какой объект? Да тот самый, который реализует интерфейс IDataRow. E> E>Или для того, чтобы закачиваться на сторону клиента вместе с объектом. То же может быть. На примере Java-апплетов что-то подобное уже изобреталось.
E>Только может быть и другая точка зрения. У каждого клиента может быть свой интерфейс к данным. Т.е. фактически, объект SomeObject, который лежит в БД может при загрузке в одного клиента иметь совсем другой интерфейс, чем при загрузке в другого клиента.
Именно это и есть то, чего хотелось бы избежать. Это нарушение инкапсуляции, а стало быть — неплохой способ выстрелить в ногу себе и окружающим. Объяснение чуть ниже: E>Например, класс Point для чертежа CAD системы может иметь несколько реализаций (но одно представление данных) -- одна реализация для использования в редакторе чертежей, одна реализация для использования в программе печати чертежей, одна реализация для программы подсчета количества требуемых для реализации нарисованной на чертеже детали материалов и т.д.
Ну, ООП в таких случаях говорит — объект обязан реализовывать несколько интерфейсов. E> В таких условиях в централизованном хранении методов классов на сервере нет смысла.
Только централизованная реализация этих интерфейсов позволяет гарантировать целостность объектов. Это ты конечно здорово придумал — иметь разные реализации. Ага, один клиент использует пару методов A и B. A переводит объект из одного целостного состояния (1) в другое (2) , и B этим пользуется — он точно знает, что никакого состояния 3 быть не может. А другой клиент использует метод С, который чихать на это хотел, и переводит тот же объект в состояние, непонятное для С. Поздравляем, выстрел в ногу произведен.
Более того, мы вынуждены доверять каждому клиенту. Представь себе банковскую систему. Никакого поведения в базе нет. Клиент вытаскивает к себе банковский счет, и оппа! у него на миллон долларов больше.
E>Так же, если класс объекта в БД может иметь различные реализации в коде клиентов, не понятно, какую из реализаций какого-то метода объекта использовать при выполнении запроса. Запрос от редактора чертежей -- это одно. А запрос от программы печати чертежа -- это уже совсем другое.
Вот именно. Поэтому классу объекта в клиент-серверной БД крайне противопоказано иметь реализации на клиенте. Чтобы не было понятно, какую реализацию использовать. E> E>Если речь идет о неуправляемых языках, таких как ObjectPascal или C++, то хранение методов объектов в БД -- это что вообще? Наличие dll-ки рядом с БД и ее ручная подгрузка сервером БД с реализацией обращений к функциям из этой dll? E>В некоторых случаях создание таких dll будет настолько трудоемкой задачей, что клиенты БД просто не будут этой возможностью пользоваться.
Забей. Технические детали — не главное. Не вижу никаких причин считать создание таких DLL неподъемной задачей. Тебя же не смущает тот факт, что можно встраивать свои компоненты в IDE Dalphi? Армейский норматив на реализацию такой DLL — 4 минуты. И после этого самопальные объекты прекрасным образом сериализуются и десериализуются. С точки зрения возможности никаких проблем не существует. Трудности использования неуправляемого кода относятся к разделам производительности, устойчивости, и безопасности. Не клиентам будет слишком тяжело, а сервер не рискнет гонять внутри себя код, который может вызвать проход по памяти и прочие разрушительные последствия. E>
E>В моем понимании ООБД -- это прежде всего поддержка понятия наследования по отношению к хранящимся в ней данным.
Внимание, вопрос: нафига нужно это наследование при отсутствии полиморфизма? Какой у него сценарий использования? И чем это отличается от банальной RDBMS? E>Инкапсуляция и полиморфизм -- это уже поведение, а не данные. А поведение определяется программой, которая данные использует. Но никак не данными.
С моей точки зрения, ООБД — это не столько хранилище, сколько средство создания серверов приложений. Т.е. замкнутых провайдеров определенной функциональности. Современные RDBMS вполне могут использоваться как самостоятельные app-сервера. Вот только программировать мало-мальски сложные сервера приложения с их помощью довольно-таки затруднительно. Хочется некоторого упрощения. Вот авторы ODMG сели в лужу именно благодаря тому, что декларировали, с одной стороны, наличие поведения у объектов (потому как иначе бы их никто всерьез не воспринял), а с другой стороны решили "пусть это поведение реализует кто-нибудь другой". В итоге ODMG так и остался мертворожденным. В том виде, в котором он существует, он не в состоянии конкурировать с RDBMS.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Все что было тобой написано -- правильно. Но правильно только с одной точки зрения. Просто у меня другая точка зрения.
И я считаю, что ООБД не смогли достичь значимых результатов именно потому, что на ООП есть слишком много разных точек зрения. И все они имеют право на жизнь. А некоторые -- даже жизнеспособные реализации. Здесь можно провести аналогию с ОО языками: С++, Java, C#, Smalltalk, Python и Ruby -- объектно ориентированные языки. Но они слишком разные.
Поэтому мой ответ ниже -- это не возражения на твои высказывания, а, скорее, попытка объяснить свою позицию.
E>>Ведь база данных -- это хранилище данных. Для чего там код? S>Занятный поинт
Может быть. Но я попробую его объяснить ниже.
E>> E>>Чтобы исполнятся во время выполнения запросов на серверной стороне, например. E>>Ok. Здесь это было бы полезно. Может быть. А может быть было бы достаточно в языке запросов простых примитивов сравнения. S>Гм. Простые примитивы сравнения уже есть. В RDBMS. Почему-то оказывается, что их не хватает. Если хватает, то зачем какие-то ОО в названии?
Сейчас попробую на пальцах объяснить, чем, на мой взгляд, ООБД отличаются от РСУБД.
Мне не нужно вручную разбирать объект на составляющие его атрибуты, чтобы записать его в БД. И не нужно собирать объект из разных атрибутов, чтобы прочитать. Т.е. вместо 'INSERT ...' я просто делаю (при неявной стабильности) new(db) SomeObject(...) или (при явной стабильности) db.store( new SomeObject( ... ) ).
Если операции INSERT и SELECT в РСУБД от меня скрывает какой-нибудь O/R Mapping Tool, то мне становится фиолетово, работаю ли я с ООСУБД или (O/R Mapping Tool + РСУБД). Но тут, как мне помнится, не все было ладно, т.к. O/R Mapping имел серьезные ограничения. Да и производительность такого меппинга могла в некоторых случаях проседать.
Например, на попытке сохранить в реляционной таблице атрибут объекта, который является вектором или списком (т.е. структурой данных, для которых важен порядок следования элементов). Сохранение/извлечение таких атрибутов в РСУБД является дорогой операцией по сравнению с ООСУБД.
Т.е., имхо, ООСУБД позволяет программе на ОО языке без проблем обеспечивать стабильность данных. Предоставляя при этом программе такие возможности, как защита данных, атомарные транзакции, многопользовательский режим работы и т.д. В том числе и язык запросов, хотя, имхо, при работе с объектными данными более естественным является навигационный подход.
E>>Например, если БД содержит огромное количество структурированной измерительной информации (Objectivity в CERN, как мне помниться, как раз для этого и применялась), то большинство объектов в ней вообще не нуждаются в методах. S>Как, впрочем, и в объектах. Я плохо знаком с тем, что хранит CERN. Подозреваю, что у них с теми объектами, которые мы привыкли видеть в ООП, общего мало или вообще ничего.
Я то же не знаком, но когда-то сталкивался с задачей сохранения измерительной информации в АСУТП и имитационном моделировании. Там, например, последовательность измерений для какого-то объекта могла представляться чем-то вроде:
// Один кортеж данных, снятых с одного измерительного устройства за один замер.class data_packet_t
{
protected:
std::vector< float > m_values;
...
};
// Один одномоментный замер с нескольких устройств.class measure_t
{
protected:
// Время проведения замера.
date_time_t m_when;
// Список устройств, с которых были сняты замеры и
// снятые значения.
std::map< std::string, data_packet_t > m_data;
...
};
// Результаты замеров для одного устройства.class object_measurement_session_t
{
protected :
std::list< measure_t > m_data;
...
};
S>Кстати, я встречал такое мнение, что ООБД — это "способ придания семантики данным типа BLOB".
Хороше мнение. Пожалуй, я его в чем-то разделяю.
Но есть важное отличие данных в ООБД от данных в BLOB: ООБД поддерживает эволюцию схемы данных. Например, ООБД позволит поменять тип значений в data_packet_t::m_values с float на double.
E>>Или БД, которые содержат чертежи из CAD систем. Большинство объектиков в них будут какими-нибудь точками, многоугольниками, ломанными и окружностями. S>Пардон за оффтоп, но можно мне вообще объяснить, зачем чертежи CAD систем хранить в БД? Почему не использовать более традиционное хранилище? Я еще понимаю GIS-системы: там есть и многопользовательская работа с едиными данными, и нетривиальные запросы (которые имеет смысл исполнять в клиент-серверной архитектуре). А в CAD-то зачем? Чертеж есть вроде как неделимая сущность... Там вообще на серверной стороне даже структуры вроде не надо.
На самом деле могут быть крутые CAD системы для проектирования, скажем, самолетов или автомобилей. Один чертеж может одновременно быть затребован несколькими участниками разработки одновременно -- одним для редактирования, одним для печати, третьим для оценки и т.д.
E>>Для которых поддержка методов в БД так же может быть избыточной. Для таких БД вообще поддерживать методы не имеет смысла. Но вот объектную-ориентированность они поддерживать должны -- извлеченный из БД объект должен становиться точно таким же объектом в программе, которым он был до записи в БД. S>Это не имеет никакого отношения к объектной ориентированности. Точнее, объектная ориентированность здесь не имеет отношения к базе данных. Если подходить с такой мерой, то окажется, что даже dBase поддерживает объектную-ориентированность, поскольку объект, записанный в БД, становится точно таким же объектом при чтении. Какой объект? Да тот самый, который реализует интерфейс IDataRow.
Не очень понял про IDataRow. Если объект однозначто представляется строкой таблицы, то важно, кто предоставляет IDataRow и кто отвечает за реализацию этого интерфейса объектом. Если IDataRow является частью ООСУБД (ее клиентской библиотеки) и реализация IDataRow делается не мной вручную, а инструментом ООСУБД, то мне без разницы, что под этим всем лежит dBase.
E>> E>>Или для того, чтобы закачиваться на сторону клиента вместе с объектом. То же может быть. На примере Java-апплетов что-то подобное уже изобреталось.
E>>Только может быть и другая точка зрения. У каждого клиента может быть свой интерфейс к данным. Т.е. фактически, объект SomeObject, который лежит в БД может при загрузке в одного клиента иметь совсем другой интерфейс, чем при загрузке в другого клиента. S>Именно это и есть то, чего хотелось бы избежать. Это нарушение инкапсуляции, а стало быть — неплохой способ выстрелить в ногу себе и окружающим. Объяснение чуть ниже: E>>Например, класс Point для чертежа CAD системы может иметь несколько реализаций (но одно представление данных) -- одна реализация для использования в редакторе чертежей, одна реализация для использования в программе печати чертежей, одна реализация для программы подсчета количества требуемых для реализации нарисованной на чертеже детали материалов и т.д. S>Ну, ООП в таких случаях говорит — объект обязан реализовывать несколько интерфейсов. E>> В таких условиях в централизованном хранении методов классов на сервере нет смысла. S>Только централизованная реализация этих интерфейсов позволяет гарантировать целостность объектов. Это ты конечно здорово придумал — иметь разные реализации. Ага, один клиент использует пару методов A и B. A переводит объект из одного целостного состояния (1) в другое (2) , и B этим пользуется — он точно знает, что никакого состояния 3 быть не может. А другой клиент использует метод С, который чихать на это хотел, и переводит тот же объект в состояние, непонятное для С. Поздравляем, выстрел в ногу произведен.
Не понял сарказма.
Я не говорил, что клиенты должны сами реализовывать интерфейсы объектов. Такая реализация действительно может привести к подобным проблемам, равно как и глючная централизованная реализация. Я лишь сказал, что каждый клиент имеет право пользоваться только тем интерфейсом, который ему нужен. Клиенты могут получить нужные им реализации в виде .a, .lib, .so, .dll, .jar или .zip-ов вместе с нужным им прикладным ПО. Фишка вот в чем. Допустим, есть у нас класс surface_t, который описывает поверхность какой-либо части какой-либо детали в CAD системе. В БД этот класс представляется некоторой структурой:
class surface_t
{
private :
// Материал, из которого создана поверхность.
material_t * m_material;
// Геометрическая форма поверхности.
geometry_t m_geometry;
...
};
Когда объект surface_t загружается в редактор чертежей, он должен представляться классом вот с таким интерфейсом:
class surface_t
{
public :
// Запросить параметры для редактора (цвет, стиль линии, стиль заливки и т.д.)void
properties( editor_properties_t & props ) const;
// Изменить значение указанного параметра (цвета, стиля линии и т.д.)void
change_properties(
const editor_property_t & prop,
editor_undo_redo_t & undo_redo );
// Отобразить объект на чертеже (с учетом группировки, выделения и т.д.)void
paint(
editor_paint_device_t & device,
editor_selection_t & selection ) const;
...
};
Когда объект загружается в программу печати, у него может быть другой интерфейс:
class surface_t
{
public :
// Отобразить на указанном устройстве.void
draw( paint_device_t & device ) const;
...
};
Для других целей у этого объекта будут другие интерфейсы. Теперь, собственно, вопрос состоит в том, должны ли реализации всех интерфейсов объекта загружаться на машину клиента, если он загружает этот объект для какой-то специфической цели (оценки стоимости используемых материалов, например)?
Если да, то во что это может вылиться, ведь тогда с кодом методов объекта потребуется тянуть и зависимости, и зависимости зависимостей.
Если нет, то чем это отличается от того, о чем я говорил?
S>Более того, мы вынуждены доверять каждому клиенту. Представь себе банковскую систему. Никакого поведения в базе нет. Клиент вытаскивает к себе банковский счет, и оппа! у него на миллон долларов больше.
А банковский клиент стало быть должен доверять коду, который он скачивает вместе с объектом с банковского сервера?
E>>Так же, если класс объекта в БД может иметь различные реализации в коде клиентов, не понятно, какую из реализаций какого-то метода объекта использовать при выполнении запроса. Запрос от редактора чертежей -- это одно. А запрос от программы печати чертежа -- это уже совсем другое. S>Вот именно. Поэтому классу объекта в клиент-серверной БД крайне противопоказано иметь реализации на клиенте. Чтобы не было понятно, какую реализацию использовать.
Мне кажется, что в твоей фразе есть противоречие. По крайней мере я не понял о чем ты.
E>> E>>Если речь идет о неуправляемых языках, таких как ObjectPascal или C++, то хранение методов объектов в БД -- это что вообще? Наличие dll-ки рядом с БД и ее ручная подгрузка сервером БД с реализацией обращений к функциям из этой dll? E>>В некоторых случаях создание таких dll будет настолько трудоемкой задачей, что клиенты БД просто не будут этой возможностью пользоваться. S>Забей. Технические детали — не главное. Не вижу никаких причин считать создание таких DLL неподъемной задачей. Тебя же не смущает тот факт, что можно встраивать свои компоненты в IDE Dalphi? Армейский норматив на реализацию такой DLL — 4 минуты. И после этого самопальные объекты прекрасным образом сериализуются и десериализуются. С точки зрения возможности никаких проблем не существует.
Существует, если сервер на Unix-е, а клиентский код под Windows и тянет за собой множество third party библиотек.
S> Трудности использования неуправляемого кода относятся к разделам производительности, устойчивости, и безопасности. Не клиентам будет слишком тяжело, а сервер не рискнет гонять внутри себя код, который может вызвать проход по памяти и прочие разрушительные последствия.
И это тоже очень веская причина для того, чтобы для C++ объектов код на сервере не хранить.
E>>
E>>В моем понимании ООБД -- это прежде всего поддержка понятия наследования по отношению к хранящимся в ней данным. S>Внимание, вопрос: нафига нужно это наследование при отсутствии полиморфизма? Какой у него сценарий использования? И чем это отличается от банальной RDBMS?
А в RDBMS можно сделать наследование для таблиц. Т.е. сказать, что вот эта таблица является наследницей вот этой (включает в себя все существующие столбцы и еще несколько других). А затем, чтобы при изменении базовой таблице соответствующим образом автоматически были модифицированны все производные от нее таблицы.
А отличается как раз поддержкой эволюции схемы данных.
E>>Инкапсуляция и полиморфизм -- это уже поведение, а не данные. А поведение определяется программой, которая данные использует. Но никак не данными. S>С моей точки зрения, ООБД — это не столько хранилище, сколько средство создания серверов приложений. Т.е. замкнутых провайдеров определенной функциональности. Современные RDBMS вполне могут использоваться как самостоятельные app-сервера. Вот только программировать мало-мальски сложные сервера приложения с их помощью довольно-таки затруднительно. Хочется некоторого упрощения. Вот авторы ODMG сели в лужу именно благодаря тому, что декларировали, с одной стороны, наличие поведения у объектов (потому как иначе бы их никто всерьез не воспринял), а с другой стороны решили "пусть это поведение реализует кто-нибудь другой". В итоге ODMG так и остался мертворожденным. В том виде, в котором он существует, он не в состоянии конкурировать с RDBMS.
У меня другая точка зрения. Сервера приложений -- это только одно из применений ООСУБД.
Имхо, главное -- это предоставление ОО программам комфортных условий для стабилизации их объектных данных.
А причин, по которым ООСУБД сели в лужу -- множество. Ты назвал только одну из них.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Andrei N.Sobchuck пишет:
>>> Конечно же собственно серверные приложения. Не важно, под чем они >>> работают. Вся фишка в том, что современная наука никак не помогает >>> писать мало-мальски нетривиальные серверные приложения. Например, >>> реализация банального SMTP-релея представляет собой headache. >> Из-за дьявольски сложного семейства почтовых стандартов. Можешь еще > Десяток команд SMTP — где там сложность?
В разборе писем, разборе адресов (никто не пользуется UUCP, а в
стандарте-то он остался), роутинге, резольвинге имен и т.д.
Известный факт: больше всего стандартов RFC именно о email.
Здравствуйте, Sinclair, Вы писали:
S>С моей точки зрения, ООБД — это не столько хранилище, сколько средство создания серверов приложений. Т.е. замкнутых провайдеров определенной функциональности. Современные RDBMS вполне могут использоваться как самостоятельные app-сервера. Вот только программировать мало-мальски сложные сервера приложения с их помощью довольно-таки затруднительно. Хочется некоторого упрощения. Вот авторы ODMG сели в лужу именно благодаря тому, что декларировали, с одной стороны, наличие поведения у объектов (потому как иначе бы их никто всерьез не воспринял), а с другой стороны решили "пусть это поведение реализует кто-нибудь другой". В итоге ODMG так и остался мертворожденным. В том виде, в котором он существует, он не в состоянии конкурировать с RDBMS.
Вы просто читаете мои мысли.
Я тоже убежден в том, что ООСУБД ака Versant могут быть действительно полезны именно в озвученой вами парадигме.
Здравствуйте, Cyberax, Вы писали:
C>Сложность все равно O(n) останется, тогда как в RDB в таблице с индексом C>по возрасту этот запрос займет O(log n) времени.
А кто в ООБД отменил индексы?
C>Конечно, можно взять в ООБД отсортированную по возрасту коллекцию людей, C>и потом уже по ней выполнить поиск, но такой подход будет изморфен RDBшному.
И что в этом плохого? К тому же — индекс можно строить независимо от вида коллекции.
Здравствуйте, Cyberax, Вы писали:
C>Sinclair пишет:
>> C>Тогда непонятно ЧЕМ же OODB отличается от RDB. >> Тем, что в RDB нет инкапсуляции, наследования и полиморфизма.
C>В хранилище ООБД инкапсюляции нет, как и в RDB.
В хранилище нет. В ООDB да. В хранилище ООБД только состояние объектов. C>Наследование и C>полиморфизм замечательно выражаются в RDB в виде объединенных по PK C>таблиц (возможно с полями-дискриминаторами).
Это всего лишь один из самых простых и самых неэффективных способов маппирования объектов в RDBMS.
C>То есть на практике объектные модели (за исключением самых извращенных) C>вполне прилично ложатся в RDB.
Ну почти да. Только для этого нужно очень много дописать. И учитывая удаленность хранилища и самой системы эффективности достойной ООДБ ты точно не получишь
>> Посмотрите этот бенчмарк: >> http://www.middlewareresearch.com/torpedo/results.jsp >> Так что, как видно из результатов, Hibernate не так уж и хорош...
C>А я могу придумать бенчмарк, где наша внутренняя ORM будет выигрывать. C>TORPEDO — это сравнение по скорости, а практика показывает, что 2-3% C>оверхеда от Hibernate практически никогда не заметны.
Дело в том, что я лишь хотел показать, что Hibernate это не панацея, как привыкли думать у нас, в России.
А насчет бенчмарка, то я тоже могу придумать такую ситуацию, в которой наша "proprietary O/R Mapping Tool" сделает все остальные...
Но как насчет таких пунктов как Scalable, Flexible (и даже Modular и EasyToUse)?
За удовлетворение всем таким требованиям и можно поступится быстродействием в конкретной задаче, и получить универсальный инструмент...
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, GlebZ, Вы писали:
GZ>>Здравствуйте, vdimas, Вы писали:
V>>>СУБД — это ср-во хранения больших объемов данных на ВНЕШНЕМ носителе таким образом, чтобы обеспечивать быстое извлечение необходимых данных в оперативную память. Для организации этого мы используем ЛОГИЧЕСКОЕ проедставление данных, ключи, индексы (уменьшающие размер ВНЕШНЕЙ памяти, требуемый для поиска) и пр. GZ>>Ошибка. Индексы предназначены не только для увеличения hit-ratio. Индексы — это способ убыстрения доступа к данным со сложностью O(NlogN) или O(1) для хешей. Это говорит о обязательности индекса при наличии большого количества объектов. А БД работает именно с большим кол-вом объектов.
V>ну и где мое высказывание противоречит твоему замечанию
Это дополнение которое перечеркивают твое следующее высказывание
Тогда ООП-хранилища и "покажут" этой реляционке, с ее суррогатными ключами и индексами.
V>могу еще пройтись по твоим индексам со сложностью поиска O(NlogN) для физического хранения... какой здравомыслящий человек будет использовать последовательный индекс при хранении в памяти больших наборов данных? кеши рулят...
Я. Может я и не здравомыслящий, но для алгоритмов с большим набором данных строить B+ индекс(или хотя бы чистый бинарник) — первое дело. Иметь одновременно сортированный список с быстрым доступом и вставкой, с возможностью адаптирования доступа алгоритмов по некоторому range — не самое плохое предприятие.
А учитывая то, что мы работаем потенциально с большим набором данных — то расходы на B+ на порядок меньше чем расходы на тупой доступ к миллионам объектов.
С уважением, Gleb.
PS: только не надо намекать на хеши Net. Оссобенно в связи с их тактикой пересчета хеша. Для больших данных — это нереальный алгоритм.
AR>>А почему бы просто не подождать до тех пор, пока они не подгрузятся в кэш по какой-либо иной надобности? А пока просто оставить специальную метку на месте удаленного объекта. Т.е. ссылки редактировать не сразу, а только по мере обращения к соответствующим объектам? GZ>Тут встанет другая проблема. Транзакционный механизм с их savepoint's.
Что то вы не так поняли. Я не имел ввиду никакого нарушения транзакционной целостности. Просто внутренние механизмы ООСУБД вовсе не обязаны физически удалять с диска (исправлять) те элементы, которые мы удалили. Достаточно пометить этот элемент как удаленный, а дальше — работа GC, который может исполняться асинхронно вне транзакции. То же самое и с исправлением ссылок. Если после поднятия ссылки (уже в другой задаче) оказывается, что она указывает на помеченный как удаленный элемент, то без уведомления приложения СУБД сама может обнулить соответсвующую ссылку и передать дальше уже null, а объект на диске исправить (вписать нул в хначение ссылки). Это очень похоже на то, как в FastObjects работает механизм версионности. Например, если мы исправили описание класса и удалили один из его атрибутов, то это вовсе не значит, что СУБД тут же перелопатит всю базу и изменит записи всех объектов данного класса (хотя мы и можем заставить ее сделать это). Вместо этого она будет править хранимые объекты только по мере их очередного редактирования, автоматически переводя их в новую версию при сохранении.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, Alexey Rovdo, Вы писали:
AR>>Что то вы не так поняли. Я не имел ввиду никакого нарушения транзакционной целостности. Просто внутренние механизмы ООСУБД вовсе не обязаны физически удалять с диска (исправлять) те элементы, которые мы удалили. Достаточно пометить этот элемент как удаленный, а дальше — работа GC, который может исполняться асинхронно вне транзакции. То же самое и с исправлением ссылок. Если после поднятия ссылки (уже в другой задаче) оказывается, что она указывает на помеченный как удаленный элемент, то без уведомления приложения СУБД сама может обнулить соответсвующую ссылку и передать дальше уже null, а объект на диске исправить (вписать нул в хначение ссылки). Это очень похоже на то, как в FastObjects работает механизм версионности. Например, если мы исправили описание класса и удалили один из его атрибутов, то это вовсе не значит, что СУБД тут же перелопатит всю базу и изменит записи всех объектов данного класса (хотя мы и можем заставить ее сделать это). Вместо этого она будет править хранимые объекты только по мере их очередного редактирования, автоматически переводя их в новую версию при сохранении. GZ>В данном случае мы подразумеваем, что можем выловить некорректную ситуацию (независимо от типа доступа) еще на уровне обработки метаданных. Но если у нас метаданные не затронуты. В результате мы получаем запрос, в котором мы должна учитывать, что информация о удаленной ссылки не лежит именно в данном объекте. Там проблемы начнутся нехилые.
Я думаю, что здесь проблем нет. Просто такая обработка лежит на отдельном уровне абстракции. Где-то выше кэша, но ниже планировщика запросов (или какая там архитектура будет).
GZ>Что касается транзакционного механизма. Как примерно работает нормальный (я бы сказал самый распространенный) механизм транзакции. Все изменения производятся в кольцевом логе. После определенного момента — происходит сброс изменений на диск (savepoint). После этого лог можно перезаписывать. Система достаточно проста и выдерживает отключение питания. У нас получается несколько неприятная вещь. С одной стороны, часть ссылок уже нормализована, а часть нет. Как это отразится на функционировании восстановления, с ходу не скажу, но то что надо что-то делать, вполне понятно.
Здесь я так же не вижу проблемы. Главное, чтобы надежно сохранился объект-ссылка, в котором установлен признак, что она уже некорректна.
GZ>Очень интересует вопрос функционирования GC для ООБД. То бишь, в персистентном хранилище(большом и медленном). Не мог бы кто-нибудь "плюнуть" какую-нибудь ссылочку. Должна быть занятная вещь.
У Константина Книжника в Goods подобный механизм был реализован. Он даже в своей диссертации какую-то теорему доказывал на эту тему. Если не ошибаюсь о том, что объект можно удалять из БД, если он не достижим по ссылкам из других объектов.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, GlebZ, Вы писали:
GZ>Возможно я тоже чего-то не врубился. Но я описывал ситуацию, в которой удаляется сам объект. Приведу слова Alexey Rovdo: GZ>
GZ>Если после поднятия ссылки (уже в другой задаче) оказывается, что она указывает на помеченный как удаленный элемент, то без уведомления приложения СУБД сама может обнулить соответсвующую ссылку и передать дальше уже null, а объект на диске исправить (вписать нул в хначение ссылки).
S>Так вот, например, я загрузил операцию (или мне ее вернула какая-нибудь функция) и решил изменить у нее ссылку на документ. То есть переприсвоить операцию другому документу (пример, конечно неудачный, но...). Я же должен соответствующие изменения сделать и в коллекциях ссылок старого и нового документа. Т.е. все равно эти коллекции сначала придется подгрузить. Так что выделяй в отдельный объект или нет — без разницы.
Что-то я не очень понимаю в чем суть проблемы. Если по условиям задачи возможно, что в объекте "операция над документом" можно поменять ссылку на изменяемый документ (что само по себе странно), то можно организовать коллекцию ссылок таким образом, чтобы операции вставки/удаления были дешевыми. Например, вместо вектора ссылок использовать двусвязный список (каждый элемент содержит собственно ссылку + ссылки на предыдущий/следующий элементы списка) или map на основе B+ дерева.
И выше по ветви.
Речь шла об объекте-документе, у которого есть список ссылок на операции над документом. И необходимо для одной операции поменять ссылку на документ. Т.е. пока ничего не удаляется, а изменяется ссылка. Хотя тоже самое может происходить, если в моем последнем примере с One_side, Another_side, какой-то из объектов будет удален.
E>>Проблемы в таком подходе, имхо, возникают, если объектиков Ref_image будет куча. Т.е. возврат к тому вопросу, с которого stalcer начинал. GZ>Именно. Либо мы начинаем обнулять (или приводить в состояние удален) ссылки при удалении объекта (по типу как ты ты привел), или мы получаем то, что я описал.
Да, ты прав.
Но я смотрю на это так. У нас есть несколько объектов между которыми установлены двунаправленные связи. Удаляя один объект изменяя его ссылки мы все равно должны будем поменять ссылки на другой строне связи. И при любом подходе суммарное время на корректировку ссылок будет приблизительно одинаковым. Но, если мы корректируем ссылки сразу при удалении объекта, мы делаем операцию удаления заведомо длительной. Если же мы корректируем ссылки при первом доступе к объекту на другой стороне связи, мы увеличиваем время доступа к нему. Но это время может быть значительно меньше, чем нам потребовалось бы на удаление с полной корректировкой ссылок. Т.е. в варианте с отложенной корректировкой мы как бы амортизируем время небольшим увеличением времени доступа к объектам.
Хорошо это или нет?
Наверное зависит от задачи.
Возможно, хорошо было бы говорить ООСУБД как именно ей следует поступать в конкретном случае.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Но я смотрю на это так. У нас есть несколько объектов между которыми установлены двунаправленные связи. Удаляя один объект изменяя его ссылки мы все равно должны будем поменять ссылки на другой строне связи. И при любом подходе суммарное время на корректировку ссылок будет приблизительно одинаковым. Но, если мы корректируем ссылки сразу при удалении объекта, мы делаем операцию удаления заведомо длительной. Если же мы корректируем ссылки при первом доступе к объекту на другой стороне связи, мы увеличиваем время доступа к нему. Но это время может быть значительно меньше, чем нам потребовалось бы на удаление с полной корректировкой ссылок. Т.е. в варианте с отложенной корректировкой мы как бы амортизируем время небольшим увеличением времени доступа к объектам.
Тут IMHO не все так однозначно. Изменение ссылки точно такая-же логгируемая операция, как и любое изменение объекта. То есть, при изменении, мы должны записать об этом в конце транзакции в лог. Попробуем рассмотреть оба варианта с точки зрения работы лога и транзакций.
В первом случае мы получаем, что при окончании транзакции мы сохраняем записи всем скопом в лог, и у нас при этом они кладуться в одну или несколько последовательных страниц.
Во втором случае, у нас в случае если транзакция read-only, мы вынуждены открыть ее (а я думаю лучше по соседству другую) как updatable. Но при этом, непонятна длительность этой транзакции, и количество данных которое должно быть сохранено существенно меньше чем размер страницы.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, GlebZ, Вы писали:
GZ>>Здравствуйте, eao197, Вы писали:
GZ>>Тут IMHO не все так однозначно. Изменение ссылки точно такая-же логгируемая операция, как и любое изменение объекта. То есть, при изменении, мы должны записать об этом в конце транзакции в лог. Попробуем рассмотреть оба варианта с точки зрения работы лога и транзакций. GZ>>В первом случае мы получаем, что при окончании транзакции мы сохраняем записи всем скопом в лог, и у нас при этом они кладуться в одну или несколько последовательных страниц. GZ>>Во втором случае, у нас в случае если транзакция read-only, мы вынуждены открыть ее (а я думаю лучше по соседству другую) как updatable. Но при этом, непонятна длительность этой транзакции, и количество данных которое должно быть сохранено существенно меньше чем размер страницы.
E>Я тоже думаю, что лучше другую. И сразу же ее зафиксировать.
Но тогда получается, что при минимуме данных (там получается практически несколько байт) придется записывать целую страницу.
Я бы пошел дальше. Например организовал отдельный (системный) лог который бы фиксировался либо при достижения объема страницы, либо перед savepoint'ом.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, GlebZ, Вы писали:
GZ>>Но предполагаю, поскольку это предназначается для ORM, то при удалении будет генерится очень нехилый select или набор select'ов для проверки как возможности удаления, так и для удаления связанных. S>Ну, вот RDBMS например этого почему-то не боятся.
А вот программеры боятся. Каждая вторая база не удаляет ничего. Возьми хотя бы RSDN для примера. А все потому, что логика сложная получается. S>Delete всегда проверяет все foreign key. И ничего — вроде как-то живет. В основном благодаря тому, что FK — это всегда индекс; а также потому, что этих FK редко бывает много. Ну сослались на меня из десяти мест — это уже какая-то экзотика пошла. S>Правда, в OODBMS тут есть некоторая тонкость, связанная с более слабой типизацией. В RDBMS у нас FK всегда попадает ровно в одну таблицу, а стало быть и в обратную сторону связей будет немного. А в ODBMS у нас ссылка может указывать на любого потомка. Так что это может привести к увеличению области сканирования: при использовании везде ссылок на System.Object придется при каждом удалении проверять абсолютно все ссылочные поля!
При удалении System.Object всегда можно определить его действительный тип. Это сократит количество задействованных ссылок. Но тут есть другое увеличение, в этом может участвовать не один объект а целый граф. Ну например, у нас есть несколько связанных логически удаленных объектов. В некоторых из них есть ссылки которые удерживают этот граф от уничтожения. S>Без практики применения невозможно сказать, насколько проверка наличия ссылок на себя в типичной OODB дороже, чем в RDB. GZ>>Возможно здесь подсчет ссылок был бы полезней, если бы не его проблемы и требования того, что ORM можно напустить практически на любую базу. S>Сам по себе подсчет ссылок — всего лишь кэширование результатов поискового запроса. Этакая денормализация.
Я все больше о ней думаю... Но пока это все только прикидки, когда делать буду (и что получится в результате) пока не знаю.
Здравствуйте, Serginio1, Вы писали:
S> Опять же для Б+ деревьев при определенном использовании верхнии уровни находятся в кэше процессора, поэтому поиск в них на больших данных оазывается быстрее, чем бинарный поиск в массиве с проинлайнниным компаратором, в отличие от компараторов Б+ (TLSD).
Интересный аргумент, и наверняка он неплохо работает в задачах многократного циклического поиска по одной и той же таблице.
К сожалению, в большинстве случаев, при работе серверов приложений, активно обрабатывающих запросы, производится постоянный поиск в сотнях подобных кешей.
Если вообще рассматривать сегодняшнее положение вещей (а не гипотетическую тему этой ветки — все данные в ОП), то кешировать я стараюсь лишь весьма разумные объемы частоиспользуемых данных (в основном — справочного характера, или же объекты, численность которых по самой сути не превышает нескольких тысяч экземпляров). Подобное кеширование справочных данных зачастую уменьшает сложность запросов к базе (меньше Join-ов, мои "типизированные" джоины работают гораздо быстрее). Соревноваться же в быстродействии и надежности обработки данных с ведущими СУБД на действительно больших объемах — явно неблагодарная задача.
Здравствуйте, stalcer, Вы писали:
S>Во-во. "редактирование основных объектов-контейнеров приводит к поднятию соответствующего объекта BiLink" — Это как? То есть соотвествующие объекты (PObject) с другой стороны будут подгружены или нет. Чего-то непонятно написано.
AR>>Но при этом второй (множество) связанный с ним по двунаправленной ссылке объект не затрагивается — изменяются только объекты BiLink.
S>Это как? Объект BiLink является же полем (т.е. частью состояния) хранимого объекта.
Я понимаю так, что здесь мы имеем дело с требя объектами. Два связанных объекта и объект-связь BiLink между ними.
A -> BiLink <- B
Всякий раз делая что-то с объектами A или B (удаляя или редактируя параметры связи) мы поднимаем объект BiLink (но не объект на другом конце связи). В случае one-to-many это выглядит так:
Вообщем ситуация такая: я уже не знаю, куда зашли разговоры в соседней ветке "Объектно-ориентированные БД: основные принципы, ..." поэтому хочется некоторые вещи выделить отдельно.
Вот, например, на форуме SQL.ru было высказано следующее мнение: (Хочется узнать что думаете об этом Вы)
Джентельмены.
Давайте забудем (и по крайней мере сделаем вид что отвлеклись от) все что здесь уже говорилось про объектные базы и Версант. Предлагаю более вообще не обсуждать теорию.
Простейшая формулировка как хранит данные и работает Версант (в отличие от реляционных баз):
1. Версант — это "якобы объектное хранилище". Методы объектов не выполняются и не хранятся. Хранятся только данные (структуры данных). Как в РСУБД. Буду нывать далее структурами данных Версант. Струры данных самые разнообразные — это и массивы, коллекции (вложенные коллекции), и указатели на другие объекты и пр. На эти коллекции маппируются вложенные коллекции классов (1-n). На указатели на объекты — ссылки n-m.
2. Версант (ядро) ничего не знает про Яву, с++, Smalltalk, whatever.
Средства доступа к Версанту на Яве "преобразуют" Ява объекты в структуры данных Версант. Средства доступа к Версанту на с++ "преобразуют" с++ объекты в структуры данных Версант. Предыдущие 2 предложения применимы к любым "обектным" языкам. Не буду их копировать.
3. Средства доступа.
1. Командная строка (аля sqlplus). Сама по себе не объектна. Соответственно, все запросы из командной строки возвращают структуры данных Версант. И тупо их печатают.
2. Средства доступа к Версанту на Яве.
2.1 Доступ по спецификации JDO. Это средство доступа ответственно за преобразование пришедших данных Версант в классы Ява. В соответствии со стандартом JDO, имеет свой собственный язык JDOQL. Это же средство ответственно за трансляцию JDOQL в запросы/вызовы процедур/чтоугодно нативное для Версант.
2.2 Доступ по АПИ Версант. Обеспечивает доступ непосредственно к структурам данных Версант. Запросы (по моему) на языке VQL. Имея этот доступ, можно реаливать любой мэппинг пришедших структур данных Версант на классы Ява.
2.3 Доступ по технологии Transparent Persistance. Просто вызывая функции Ява но изменению значения полей объектов, автоматически происходит преобразование данной системой доступа объектов в структуры данных Версант и их запись. Основной плюс — полное отсутствие обращений по обслуживанию сохранения объектов (поэтому и называется Transparent...)
2.4 Доступ по спецификации JDBC. Не знаю, не работал.
Единственное, что нельзя релизовать с точки зрения хранения структур в Яве — это с++ множественное наследование. Устраняется проблема путем либо интерфейсов, либо ручного маппинга.
Ессно, есть средства доступа для других объектных языков.
4. Средства ссылочной целостности — полные аналоги check constraints, foreign key, primary key. Есть хранимые процедуры и триггеры.
5. План запросов — есть хрень показывающая план запроса.
Здравствуйте, BaZa, Вы писали:
BZ>Вообщем ситуация такая: я уже не знаю, куда зашли разговоры в соседней ветке "Объектно-ориентированные БД: основные принципы, ..." поэтому хочется некоторые вещи выделить отдельно.
BZ>Вот, например, на форуме SQL.ru было высказано следующее мнение: (Хочется узнать что думаете об этом Вы)
Так а в чем, собственно, вопрос состоит? Согласны ли читатели форума с приведенным мнением?
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
BZ>>Вот, например, на форуме SQL.ru было высказано следующее мнение: (Хочется узнать что думаете об этом Вы)
E>Так а в чем, собственно, вопрос состоит? Согласны ли читатели форума с приведенным мнением?
Мне просто, например, интересно, так ли необходимо хранение методов в ООСУБД (как в Gemstone и O2)?
Здравствуйте, BaZa, Вы писали:
BZ>>>Вот, например, на форуме SQL.ru было высказано следующее мнение: (Хочется узнать что думаете об этом Вы)
E>>Так а в чем, собственно, вопрос состоит? Согласны ли читатели форума с приведенным мнением?
BZ>Мне просто, например, интересно, так ли необходимо хранение методов в ООСУБД (как в Gemstone и O2)?
Имхо, хранение методов возможно только для управляемых языков (типа C#, Java, Python, Ruby, Smalltalk, ...). Если речь о C++, то сделать хренение методов объектов в БД будет на порядок (а то и на несколько) сложнее. Да и не понятно, будет ли в случае C++ от этого какая-то польза.
А дальше разработчики ООСУБД должны сами для себя решить, нужна ли им такая функциональность или нет. Например, если ООСУБД предназначается для использования в CAD системах, то от методов объектов в БД пользы может никакой и не быть. Равно как и в случаях, когда ООСУБД используется для накопления больших объемов измерительных данных (хотя не знаю, может здесь от методов какая-то польза и будет). А если ООСУБД предназначена для enterprise-задач, то от помещения части бизнес-логики в методы хранящихся в БД объектов польза может быть существенная.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, BaZa, Вы писали: BZ>Мне просто, например, интересно, так ли необходимо хранение методов в ООСУБД (как в Gemstone и O2)?
Ну, вообще-то, лично я бы постеснялся назвать базу без хранения методов объектно-ориентированной. Поскольку из пяти концепций объектно-ориентированного программирования поддерживаются только две: идентифицируемость и наследование. О поведении, вместе с инкапсуляцией и полиморфизмом, можно забыть. Не вполне очевидно, нужно ли вообще наследование без полиморфизма.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, eao197, Вы писали:
E>Сейчас попробую на пальцах объяснить, чем, на мой взгляд, ООБД отличаются от РСУБД.
E>Мне не нужно вручную разбирать объект на составляющие его атрибуты, чтобы записать его в БД. И не нужно собирать объект из разных атрибутов, чтобы прочитать. Т.е. вместо 'INSERT ...' я просто делаю (при неявной стабильности) new(db) SomeObject(...) или (при явной стабильности) db.store( new SomeObject( ... ) ).
Гм. Это, опять же, не имеет никакого отношения к устройству самой СУБД. С тем же успехом ты мог выполнить совершенно процедурный T-SQL:
exec CreateSomeObject @param1, @param2
Более того, в отличие от процедурных языков, где инкапсуляция была всего лишь договоренностью, то в РСУБД можно добиться инкапсуляции при помощи административных мер. Т.е. достаточно ограничить доступ к данным и заставить использовать только хранимые процедуры — и вуаля, целостность гарантирована.
E>Если операции INSERT и SELECT в РСУБД от меня скрывает какой-нибудь O/R Mapping Tool, то мне становится фиолетово, работаю ли я с ООСУБД или (O/R Mapping Tool + РСУБД). Но тут, как мне помнится, не все было ладно, т.к. O/R Mapping имел серьезные ограничения. Да и производительность такого меппинга могла в некоторых случаях проседать.
Проблема O/R маппинга ровно одна — в этом подходе код исполняется на клиенте.
E>Например, на попытке сохранить в реляционной таблице атрибут объекта, который является вектором или списком (т.е. структурой данных, для которых важен порядок следования элементов). Сохранение/извлечение таких атрибутов в РСУБД является дорогой операцией по сравнению с ООСУБД.
Очень странно. Никаких проблем с хранением таких атрибутов в РСУБД нету! Это же в чистом виде структурно-процедурное программирование. Ну где здесь объектность? Список в РСУБД можно хранить десятком способов, и никаких проблем с этим не будет. E>Т.е., имхо, ООСУБД позволяет программе на ОО языке без проблем обеспечивать стабильность данных. E>Предоставляя при этом программе такие возможности, как защита данных, атомарные транзакции, многопользовательский режим работы и т.д. В том числе и язык запросов, хотя, имхо, при работе с объектными данными более естественным является навигационный подход.
То же самое обеспечивает РСУБД. Уже. Зачем буквы ОО? E>Я то же не знаком, но когда-то сталкивался с задачей сохранения измерительной информации в АСУТП и имитационном моделировании. Там, например, последовательность измерений для какого-то объекта могла представляться чем-то вроде: E>
E>// Один кортеж данных, снятых с одного измерительного устройства за один замер.
E>class data_packet_t
E> {
E> protected:
E> std::vector< float > m_values;
E> ...
E> };
E>// Один одномоментный замер с нескольких устройств.
E>class measure_t
E> {
E> protected:
E> // Время проведения замера.
E> date_time_t m_when;
E> // Список устройств, с которых были сняты замеры и
E> // снятые значения.
E> std::map< std::string, data_packet_t > m_data;
E> ...
E> };
E>// Результаты замеров для одного устройства.
E>class object_measurement_session_t
E> {
E> protected :
E> std::list< measure_t > m_data;
E> ...
E> };
E>
Ну вот — типичный BLOB. Какие запросы должна обрабатывать СУБД? "Дай мне заданный object_measurement_session_t"? Нет проблем — сериализация + BLOB более чем достаточны. E>Хороше мнение. Пожалуй, я его в чем-то разделяю. E>Но есть важное отличие данных в ООБД от данных в BLOB: ООБД поддерживает эволюцию схемы данных. Например, ООБД позволит поменять тип значений в data_packet_t::m_values с float на double.
А, ну вот началось первое отличие тех ООБД, которые ты хочешь, от РСУБД: эволюция схемы. Действительно, BLOB одним альтером не сапгрейдишь. Впрочем, вряд ли ООБД сумеет самостоятельно сконвертировать данные в случаях, отличных от тривиальных float->double или short int -> int. Т.е. придется писать апгрейд-скрипт, точнее клиентскую программу, которая инстанцирует объекты старого класса, создаст по ним объекты нового класса, и сохранит новые объекты в СУБД. В реляционке даже проще — не будет проблем с частичными апгрейдами.
E>На самом деле могут быть крутые CAD системы для проектирования, скажем, самолетов или автомобилей. Один чертеж может одновременно быть затребован несколькими участниками разработки одновременно -- одним для редактирования, одним для печати, третьим для оценки и т.д.
Гм. И что? Ну вот у нас в таких случаях просто делается CheckOut из системы контроля версий. Суть в том, что в таком сценарии вообще не нужна структура на стороне сервера. Максимум, что надо — интеллектуальный Diff/Merge на стороне клиента, чтобы при конфликтах обновлений предотвратить потерю. Где здесь СУБД? Тут даже реляционка не нужна.
E>>>Для которых поддержка методов в БД так же может быть избыточной. Для таких БД вообще поддерживать методы не имеет смысла. Но вот объектную-ориентированность они поддерживать должны -- извлеченный из БД объект должен становиться точно таким же объектом в программе, которым он был до записи в БД. S>>Это не имеет никакого отношения к объектной ориентированности. Точнее, объектная ориентированность здесь не имеет отношения к базе данных. Если подходить с такой мерой, то окажется, что даже dBase поддерживает объектную-ориентированность, поскольку объект, записанный в БД, становится точно таким же объектом при чтении. Какой объект? Да тот самый, который реализует интерфейс IDataRow.
E>Не очень понял про IDataRow. Если объект однозначто представляется строкой таблицы, то важно, кто предоставляет IDataRow и кто отвечает за реализацию этого интерфейса объектом.
Ну как кто? ADO.NET. E>Если IDataRow является частью ООСУБД (ее клиентской библиотеки) и реализация IDataRow делается не мной вручную, а инструментом ООСУБД, то мне без разницы, что под этим всем лежит dBase.
Вот именно. А чего тебе еще надо? Все, чего ты хочешь, существует в природе уже лет пятнадцать как в наистабильнейшем виде.
E> Не понял сарказма. E>Я не говорил, что клиенты должны сами реализовывать интерфейсы объектов. Такая реализация действительно может привести к подобным проблемам, равно как и глючная централизованная реализация. Я лишь сказал, что каждый клиент имеет право пользоваться только тем интерфейсом, который ему нужен. Клиенты могут получить нужные им реализации в виде .a, .lib, .so, .dll, .jar или .zip-ов вместе с нужным им прикладным ПО. Фишка вот в чем. Допустим, есть у нас класс surface_t, который описывает поверхность какой-либо части какой-либо детали в CAD системе. В БД этот класс представляется некоторой структурой: E>Для других целей у этого объекта будут другие интерфейсы. Теперь, собственно, вопрос состоит в том, должны ли реализации всех интерфейсов объекта загружаться на машину клиента, если он загружает этот объект для какой-то специфической цели (оценки стоимости используемых материалов, например)?
Нет. Зачем вообще заморачиваться какими-то ООСУБД в данном случае? Ну вот рассмотрим до-XML формат Microsoft Word. Эти документы прекрасно живут в сети безо всяких СУБД. И клиенту не надо ничего тащить — всё, что ты называешь громким словом "интерфейс", просто вшито в соответствующую программу. Сервер не предоставляет никаких сервисов, кроме "сохранить объект" и "загрузить объект". С этим прекрасно справляется банальная сериализация. Поэтому у кого-то может стоять Word Professional, а у кого-то — WordPad. Вот тебе и разные интерфейсы.
S>>Более того, мы вынуждены доверять каждому клиенту. Представь себе банковскую систему. Никакого поведения в базе нет. Клиент вытаскивает к себе банковский счет, и оппа! у него на миллон долларов больше.
E>А банковский клиент стало быть должен доверять коду, который он скачивает вместе с объектом с банковского сервера?
Нет. Банковский клиент вообще не скачивает никакого кода. Банковский клиент выполняет запрос. Например, на перевод денег с одного счета на другой. На сервере при выполнении этого запроса задействуется вся мощь ОО и СУБД. Примерно так:
public static void TransferMoney(IAccount source, IAccount target, IAmout amount)
{
try
{
target.Balance += amount; // здесь выполняется офигенно полиморфный код, благодаря которому мы
source.Balance -= amount; // можем безболезненно вводить новые типы счетов. Так выглядит ОО в ООСУБД.
}
catch(Exception ex)
{
// при попадании в обработчик состояние всех объектов автоматически откатывается к тому, которое
// было на момент try. Так выглядят транзакции в ООСУБД.
Audit.Log("Failed to transfer {0} from {1} to {2}: {3}", amount, source, target, ex);
}
}
Все. Код, который нужен клиенту — это интерфейсный код: определения интерфейсов IAccount, IAmount, типы, используемые в запросах (public struct Amount: IAmount) и прочие тривиальные вещи. TLB.
E>Мне кажется, что в твоей фразе есть противоречие. По крайней мере я не понял о чем ты.
Нету E>И это тоже очень веская причина для того, чтобы для C++ объектов код на сервере не хранить.
Еще раз: это веская причина никогда не отпускать код объектов на клиента! Код не просто должен храниться на сервере, он должен только там и жить! СУБД, в которой часть работы исполняет клиент, уже доказали свою несостоятельность. Ну вот были раньше такие файл-серверные СУБД, в которых сервер предоставлял только доступ к хранилищу. А весь код, обрабатывающий запросы, хранился в клиенте. И взад-вперед летали странички диска, а уже "клиентская библиотека СУБД" придавала им смысл записей и таблиц. Проблемы с консистентностью и масштабируемостью похоронили эту идею для распределенных систем. Их вытеснили клиент-серверные СУБД. Ты сейчас предлагаешь сделать ту же ошибку — реализовать, фактически, архитектуру dBase IV. E>>>
E>>>В моем понимании ООБД -- это прежде всего поддержка понятия наследования по отношению к хранящимся в ней данным. S>>Внимание, вопрос: нафига нужно это наследование при отсутствии полиморфизма? Какой у него сценарий использования? И чем это отличается от банальной RDBMS?
E>А в RDBMS можно сделать наследование для таблиц. Т.е. сказать, что вот эта таблица является наследницей вот этой (включает в себя все существующие столбцы и еще несколько других). А затем, чтобы при изменении базовой таблице соответствующим образом автоматически были модифицированны все производные от нее таблицы.
Нет, так нельзя. А зачем? Я могу сделать это при помощи хранимых процедур. Один раз написать костяк типа create proc AlterRelatedTable и все.
E>У меня другая точка зрения. Сервера приложений -- это только одно из применений ООСУБД. E>Имхо, главное -- это предоставление ОО программам комфортных условий для стабилизации их объектных данных.
То, о чем ты говоришь, к системам управления базами данных отношения не имеет. Стабилизация объектных данных называется persistence, и для нее существует великое множество решений. Как правило, это банальная сериализация. Встроена практически во все ОО-системы, распространенные с девяностых годов и по наше время. MFC, VCL, Java и .Net поддерживают сохранение объектов. Причем и эволюция схемы решена везде (кроме как в Delphi).
От СУБД все-таки хочется чего-то более серъезного.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, eao197, Вы писали:
E>>Сейчас попробую на пальцах объяснить, чем, на мой взгляд, ООБД отличаются от РСУБД.
E>>Мне не нужно вручную разбирать объект на составляющие его атрибуты, чтобы записать его в БД. И не нужно собирать объект из разных атрибутов, чтобы прочитать. Т.е. вместо 'INSERT ...' я просто делаю (при неявной стабильности) new(db) SomeObject(...) или (при явной стабильности) db.store( new SomeObject( ... ) ). S>Гм. Это, опять же, не имеет никакого отношения к устройству самой СУБД. С тем же успехом ты мог выполнить совершенно процедурный T-SQL: S>
S>exec CreateSomeObject @param1, @param2
S>
А я и не говорил про устройство. Я говорил про работу с ООСУБД из моей ОО программы.
S>Более того, в отличие от процедурных языков, где инкапсуляция была всего лишь договоренностью, то в РСУБД можно добиться инкапсуляции при помощи административных мер. Т.е. достаточно ограничить доступ к данным и заставить использовать только хранимые процедуры — и вуаля, целостность гарантирована.
Целостность чего?
E>>Если операции INSERT и SELECT в РСУБД от меня скрывает какой-нибудь O/R Mapping Tool, то мне становится фиолетово, работаю ли я с ООСУБД или (O/R Mapping Tool + РСУБД). Но тут, как мне помнится, не все было ладно, т.к. O/R Mapping имел серьезные ограничения. Да и производительность такого меппинга могла в некоторых случаях проседать. S>Проблема O/R маппинга ровно одна — в этом подходе код исполняется на клиенте.
Опять не понимаю, о каком коде идет речь. О том, что метод TransferMoney исполняется на клиенте?
E>>Например, на попытке сохранить в реляционной таблице атрибут объекта, который является вектором или списком (т.е. структурой данных, для которых важен порядок следования элементов). Сохранение/извлечение таких атрибутов в РСУБД является дорогой операцией по сравнению с ООСУБД. S>Очень странно. Никаких проблем с хранением таких атрибутов в РСУБД нету! Это же в чистом виде структурно-процедурное программирование. Ну где здесь объектность? Список в РСУБД можно хранить десятком способов, и никаких проблем с этим не будет.
Объектность в том, что я, как программист, которому нужно сохранить в БД объект вида:
не задумываюсь о том, как атрибут polygon_t::m_points представляется в БД. Даже, если я работаю через O/R маппинг, я не должен об этом думать. Но если попробовать отобразить polygon_t::m_points на реляционную таблицу, то получится табличка со столбцами polygon_id (идентификатор объекта-полигона, которому принадлежит список), ordinal (порядковый номер элемента в списке), x, y. И чтобы поднять объект-полигон, нужно будет сделать два запроса -- один, чтобы поднять сам полигон и его атрибуты, второй -- чтобы выбрать все точки, которые составляют его атрибут m_points.
Именно из-за того, что сборка более-менее сложного объекта производится за счет нескольких запросов, вместо одной операции десериализации, O/R маппинг проигрывает по скорости чистым реляционным или объектным схемам.
E>>Т.е., имхо, ООСУБД позволяет программе на ОО языке без проблем обеспечивать стабильность данных. E>>Предоставляя при этом программе такие возможности, как защита данных, атомарные транзакции, многопользовательский режим работы и т.д. В том числе и язык запросов, хотя, имхо, при работе с объектными данными более естественным является навигационный подход. S>То же самое обеспечивает РСУБД. Уже. Зачем буквы ОО?
Затем, чтобы обеспечить эти характеристики хранилищам, в которых находятся именно объекты, а не таблицы. Для простоты можешь считать образами объектов обычные BLOB-ы, но это не совсем правильно.
E>>Я то же не знаком, но когда-то сталкивался с задачей сохранения измерительной информации в АСУТП и имитационном моделировании. Там, например, последовательность измерений для какого-то объекта могла представляться чем-то вроде: E>>
E>>// Один кортеж данных, снятых с одного измерительного устройства за один замер.
E>>class data_packet_t
E>> {
E>> protected:
E>> std::vector< float > m_values;
E>> ...
E>> };
E>>// Один одномоментный замер с нескольких устройств.
E>>class measure_t
E>> {
E>> protected:
E>> // Время проведения замера.
E>> date_time_t m_when;
E>> // Список устройств, с которых были сняты замеры и
E>> // снятые значения.
E>> std::map< std::string, data_packet_t > m_data;
E>> ...
E>> };
E>>// Результаты замеров для одного устройства.
E>>class object_measurement_session_t
E>> {
E>> protected :
E>> std::list< measure_t > m_data;
E>> ...
E>> };
E>>
S>Ну вот — типичный BLOB. Какие запросы должна обрабатывать СУБД? "Дай мне заданный object_measurement_session_t"? Нет проблем — сериализация + BLOB более чем достаточны.
Да, именно такие. Причем эффективно. За один запрос, вместо нескольких, как в случае с SQL.
E>>Хороше мнение. Пожалуй, я его в чем-то разделяю. E>>Но есть важное отличие данных в ООБД от данных в BLOB: ООБД поддерживает эволюцию схемы данных. Например, ООБД позволит поменять тип значений в data_packet_t::m_values с float на double. S>А, ну вот началось первое отличие тех ООБД, которые ты хочешь, от РСУБД: эволюция схемы. Действительно, BLOB одним альтером не сапгрейдишь. Впрочем, вряд ли ООБД сумеет самостоятельно сконвертировать данные в случаях, отличных от тривиальных float->double или short int -> int.
А это уже очень много. Особенно, если тип атрибута изменился в базовом классе, от которого в БД есть десяток-другой наследников.
Еще один тип операций в эволюции схемы данных -- изменение иерархии наследования. Т.е. добавление нового базового типа в иерархию или изъятие базового типа из иерархии.
S> Т.е. придется писать апгрейд-скрипт, точнее клиентскую программу, которая инстанцирует объекты старого класса, создаст по ним объекты нового класса, и сохранит новые объекты в СУБД. В реляционке даже проще — не будет проблем с частичными апгрейдами.
Да, в случае нетривиальных изменений такое придется делать.
E>>На самом деле могут быть крутые CAD системы для проектирования, скажем, самолетов или автомобилей. Один чертеж может одновременно быть затребован несколькими участниками разработки одновременно -- одним для редактирования, одним для печати, третьим для оценки и т.д. S>Гм. И что? Ну вот у нас в таких случаях просто делается CheckOut из системы контроля версий. Суть в том, что в таком сценарии вообще не нужна структура на стороне сервера. Максимум, что надо — интеллектуальный Diff/Merge на стороне клиента, чтобы при конфликтах обновлений предотвратить потерю. Где здесь СУБД? Тут даже реляционка не нужна.
Не скажи. Задачи бывают разные. Например, мне довелось участвовать в разработке системы конструирования АСУТП, где все данные находились в ООБД. Было очень удобно при многопользовательской работе. Один разработчик добавляет новый объект в БД, начинает его конструировать, а второй в этот момент может делать ссылки на новый объект и включать его в собственные объекты.
И тут появляется еще один момент, про который я забыл сказать -- контроль целостности ссылок. ООСУБД обязана это поддерживать. Причем контроль целостности может проявляться в двух вещах:
— запрет на уничтожение объекта, если на него есть ссылки;
— автоматическая корректировка ссылок на удаляемый из БД объект.
E>>>>Для которых поддержка методов в БД так же может быть избыточной. Для таких БД вообще поддерживать методы не имеет смысла. Но вот объектную-ориентированность они поддерживать должны -- извлеченный из БД объект должен становиться точно таким же объектом в программе, которым он был до записи в БД. S>>>Это не имеет никакого отношения к объектной ориентированности. Точнее, объектная ориентированность здесь не имеет отношения к базе данных. Если подходить с такой мерой, то окажется, что даже dBase поддерживает объектную-ориентированность, поскольку объект, записанный в БД, становится точно таким же объектом при чтении. Какой объект? Да тот самый, который реализует интерфейс IDataRow.
E>>Не очень понял про IDataRow. Если объект однозначто представляется строкой таблицы, то важно, кто предоставляет IDataRow и кто отвечает за реализацию этого интерфейса объектом. S>Ну как кто? ADO.NET.
Ты думаешь, что ADO.NET осчастливит весь мир, и кроме ADO.NET больше ничего не может быть?
E>>Если IDataRow является частью ООСУБД (ее клиентской библиотеки) и реализация IDataRow делается не мной вручную, а инструментом ООСУБД, то мне без разницы, что под этим всем лежит dBase. S>Вот именно. А чего тебе еще надо? Все, чего ты хочешь, существует в природе уже лет пятнадцать как в наистабильнейшем виде.
Так чего же все время что-то еще изобретают?
Видно, не все, что нужно есть.
E>> Не понял сарказма. E>>Я не говорил, что клиенты должны сами реализовывать интерфейсы объектов. Такая реализация действительно может привести к подобным проблемам, равно как и глючная централизованная реализация. Я лишь сказал, что каждый клиент имеет право пользоваться только тем интерфейсом, который ему нужен. Клиенты могут получить нужные им реализации в виде .a, .lib, .so, .dll, .jar или .zip-ов вместе с нужным им прикладным ПО. Фишка вот в чем. Допустим, есть у нас класс surface_t, который описывает поверхность какой-либо части какой-либо детали в CAD системе. В БД этот класс представляется некоторой структурой: E>>Для других целей у этого объекта будут другие интерфейсы. Теперь, собственно, вопрос состоит в том, должны ли реализации всех интерфейсов объекта загружаться на машину клиента, если он загружает этот объект для какой-то специфической цели (оценки стоимости используемых материалов, например)? S>Нет. Зачем вообще заморачиваться какими-то ООСУБД в данном случае? Ну вот рассмотрим до-XML формат Microsoft Word. Эти документы прекрасно живут в сети безо всяких СУБД. И клиенту не надо ничего тащить — всё, что ты называешь громким словом "интерфейс", просто вшито в соответствующую программу. Сервер не предоставляет никаких сервисов, кроме "сохранить объект" и "загрузить объект". С этим прекрасно справляется банальная сериализация. Поэтому у кого-то может стоять Word Professional, а у кого-то — WordPad. Вот тебе и разные интерфейсы.
Да, именно об этом я и говорил. Но, сериализация на клиенте может быть и банальная, да только на сервере к ней добавляются:
— защита от сбоев;
— многопользовательский режим работы;
— поддержка транзакций и блокировок;
— поддержка ссылочной целостности;
— поддержка эволюции схемы данных;
— поддержка поисковых запросов.
Да, можно все это сделать за счет сериализации+РСУБД в качестве хранилища+еще что-то для контроля ссылочной целостности и эволюции схемы данных. Только, боюсь, эффективность такого решения будет не очень высокой. Да и сложность надстройки над РСУБД может быть сравнима со сложностью самой ООСУБД.
S>>>Более того, мы вынуждены доверять каждому клиенту. Представь себе банковскую систему. Никакого поведения в базе нет. Клиент вытаскивает к себе банковский счет, и оппа! у него на миллон долларов больше.
E>>А банковский клиент стало быть должен доверять коду, который он скачивает вместе с объектом с банковского сервера? S>Нет. Банковский клиент вообще не скачивает никакого кода. Банковский клиент выполняет запрос. Например, на перевод денег с одного счета на другой. На сервере при выполнении этого запроса задействуется вся мощь ОО и СУБД. Примерно так: S>
S>public static void TransferMoney(IAccount source, IAccount target, IAmout amount)
S>{
S> try
S> {
S> target.Balance += amount; // здесь выполняется офигенно полиморфный код, благодаря которому мы
S> source.Balance -= amount; // можем безболезненно вводить новые типы счетов. Так выглядит ОО в ООСУБД.
S> }
S> catch(Exception ex)
S> {
S> // при попадании в обработчик состояние всех объектов автоматически откатывается к тому, которое
S> // было на момент try. Так выглядят транзакции в ООСУБД.
S> Audit.Log("Failed to transfer {0} from {1} to {2}: {3}", amount, source, target, ex);
S> }
S>}
S>
S>Все. Код, который нужен клиенту — это интерфейсный код: определения интерфейсов IAccount, IAmount, типы, используемые в запросах (public struct Amount: IAmount) и прочие тривиальные вещи. TLB.
Т.е. твой посыл состоит в том, чтобы ООСУБД отвечала за бизнес-логику.
А зачем? Чем существующие решения в виде серверов приложений не удовлетворяют?
Что в этом случае будет означать ОО в ООСУБД?
E>>Мне кажется, что в твоей фразе есть противоречие. По крайней мере я не понял о чем ты. S>Нету E>>И это тоже очень веская причина для того, чтобы для C++ объектов код на сервере не хранить. S>Еще раз: это веская причина никогда не отпускать код объектов на клиента! Код не просто должен храниться на сервере, он должен только там и жить! СУБД, в которой часть работы исполняет клиент, уже доказали свою несостоятельность. Ну вот были раньше такие файл-серверные СУБД, в которых сервер предоставлял только доступ к хранилищу. А весь код, обрабатывающий запросы, хранился в клиенте. И взад-вперед летали странички диска, а уже "клиентская библиотека СУБД" придавала им смысл записей и таблиц. Проблемы с консистентностью и масштабируемостью похоронили эту идею для распределенных систем. Их вытеснили клиент-серверные СУБД. Ты сейчас предлагаешь сделать ту же ошибку — реализовать, фактически, архитектуру dBase IV.
Вообще-то я ничего не предлагал. Я просто высказал свое отношение к хранению методов объектов в СУБД.
Кроме того, я вообще считаю, что развитый язык запросов в ООСУБД нужен далеко не для всех задач. Во многих случаях, с которыми я сам сталкивался, нужна была всего одна операция -- найти ссылку на объект по некоторому ключу. Далее по найденой ссылке объект извлекался из БД и весь остальной доступ осуществлялся через навигацию по ссылкам.
Да, признаю, я работал с ООСУБД в очень специфических областях. И мои взгляды на то, как должны работать ООСУБД будут отличаться от твоих. Но я продолжаю настаивать на мнении, что нельзя сделать общую, универсальную ООСУБД. В принципе.
E>>>>В моем понимании ООБД -- это прежде всего поддержка понятия наследования по отношению к хранящимся в ней данным. S>>>Внимание, вопрос: нафига нужно это наследование при отсутствии полиморфизма? Какой у него сценарий использования? И чем это отличается от банальной RDBMS?
E>>А в RDBMS можно сделать наследование для таблиц. Т.е. сказать, что вот эта таблица является наследницей вот этой (включает в себя все существующие столбцы и еще несколько других). А затем, чтобы при изменении базовой таблице соответствующим образом автоматически были модифицированны все производные от нее таблицы. S>Нет, так нельзя. А зачем? Я могу сделать это при помощи хранимых процедур. Один раз написать костяк типа create proc AlterRelatedTable и все.
Так вот в ООСУБД этого вообще делать не нужно.
E>>У меня другая точка зрения. Сервера приложений -- это только одно из применений ООСУБД. E>>Имхо, главное -- это предоставление ОО программам комфортных условий для стабилизации их объектных данных. S> То, о чем ты говоришь, к системам управления базами данных отношения не имеет. Стабилизация объектных данных называется persistence, и для нее существует великое множество решений. Как правило, это банальная сериализация. Встроена практически во все ОО-системы, распространенные с девяностых годов и по наше время. MFC, VCL, Java и .Net поддерживают сохранение объектов. Причем и эволюция схемы решена везде (кроме как в Delphi).
S>От СУБД все-таки хочется чего-то более серъезного.
А ты добавь к сериализации еще и остальные характеристики СУБД.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали: E>Т.е. твой посыл состоит в том, чтобы ООСУБД отвечала за бизнес-логику. E>А зачем? Чем существующие решения в виде серверов приложений не удовлетворяют?
Да тем, что сейчас писать сервера приложений уж очень тяжело. E>Что в этом случае будет означать ОО в ООСУБД?
Как обычно — поддержку наследования, инкапсуляции и полиморфизма. Именно этого сейчас в RDBMS нет. E>Вообще-то я ничего не предлагал. Я просто высказал свое отношение к хранению методов объектов в СУБД.
Именно. Ты предлагаешь хранить код методов на клиенте. В таком случае все действия можно выполнять только в клиенте, а СУБД всего лишь отдает сырые данные и принимает сырые данные. Темное средневековье. E>Да, признаю, я работал с ООСУБД в очень специфических областях. И мои взгляды на то, как должны работать ООСУБД будут отличаться от твоих. Но я продолжаю настаивать на мнении, что нельзя сделать общую, универсальную ООСУБД. В принципе. S>>От СУБД все-таки хочется чего-то более серъезного. E>А ты добавь к сериализации еще и остальные характеристики СУБД.
Я-то как раз не против. Вот только добавление "остальных" характеристик СУБД с неизбежностью приводит к необходимости замкнуть реализацию, т.е. хранить и исполнять код только на стороне сервера.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, eao197, Вы писали: E>>Т.е. твой посыл состоит в том, чтобы ООСУБД отвечала за бизнес-логику. E>>А зачем? Чем существующие решения в виде серверов приложений не удовлетворяют? S>Да тем, что сейчас писать сервера приложений уж очень тяжело.
Сервера приложений? Или приложения, которые работают под управлением серверов приложений?
E>>Что в этом случае будет означать ОО в ООСУБД? S>Как обычно — поддержку наследования, инкапсуляции и полиморфизма. Именно этого сейчас в RDBMS нет.
Но при этом код сосредотачивается на сервере.
E>>Вообще-то я ничего не предлагал. Я просто высказал свое отношение к хранению методов объектов в СУБД. S>Именно. Ты предлагаешь хранить код методов на клиенте. В таком случае все действия можно выполнять только в клиенте, а СУБД всего лишь отдает сырые данные и принимает сырые данные. Темное средневековье.
Может быть. Только и таких реализаций open-source не так уж и много. А коммерческие дороги.
E>>Да, признаю, я работал с ООСУБД в очень специфических областях. И мои взгляды на то, как должны работать ООСУБД будут отличаться от твоих. Но я продолжаю настаивать на мнении, что нельзя сделать общую, универсальную ООСУБД. В принципе. S>>>От СУБД все-таки хочется чего-то более серъезного. E>>А ты добавь к сериализации еще и остальные характеристики СУБД. S>Я-то как раз не против. Вот только добавление "остальных" характеристик СУБД с неизбежностью приводит к необходимости замкнуть реализацию, т.е. хранить и исполнять код только на стороне сервера.
Да, я понял твою позицию.
Имхо, это достижимо только для управляемых языков.
Т.е. C++ идет лесом, а это мне не нравиться
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали: E>Сервера приложений? Или приложения, которые работают под управлением серверов приложений?
Конечно же собственно серверные приложения. Не важно, под чем они работают. Вся фишка в том, что современная наука никак не помогает писать мало-мальски нетривиальные серверные приложения. Например, реализация банального SMTP-релея представляет собой headache. Даже если использовать RDBMS в качестве storage. Авиабилеты до сих пор приходится продавать через терминальные сервера, как и тридцать лет назад! Написать нормальный сервис продажи авиабилетов пока никому не удалось (насколько мне известно).
E>Но при этом код сосредотачивается на сервере.
Естественно.
E>Может быть. Только и таких реализаций open-source не так уж и много. А коммерческие дороги.
Так их немного именно потому, что нафиг они не упали.
E>Имхо, это достижимо только для управляемых языков.
Насколько я вижу — да. Требования стабильности, безопасности, и производительности не удается удовлетворить другим способом. E>Т.е. C++ идет лесом, а это мне не нравиться
Почему же? С++/CLI вполне подойдет.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, eao197, Вы писали: E>>Сервера приложений? Или приложения, которые работают под управлением серверов приложений? S>Конечно же собственно серверные приложения. Не важно, под чем они работают. Вся фишка в том, что современная наука никак не помогает писать мало-мальски нетривиальные серверные приложения. Например, реализация банального SMTP-релея представляет собой headache. Даже если использовать RDBMS в качестве storage. Авиабилеты до сих пор приходится продавать через терминальные сервера, как и тридцать лет назад! Написать нормальный сервис продажи авиабилетов пока никому не удалось (насколько мне известно).
Понятно. Но ты, как я понимаю, больше в сторону .Net смотришь? А в Java, имхо, в этом направлении активно копают.
E>>Может быть. Только и таких реализаций open-source не так уж и много. А коммерческие дороги. S>Так их немного именно потому, что нафиг они не упали.
E>>Имхо, это достижимо только для управляемых языков. S>Насколько я вижу — да. Требования стабильности, безопасности, и производительности не удается удовлетворить другим способом.
Вот это то и плохо.
Хотя, даже если код на стороне сервера будет управляемым, то проблемы производительности у СУБД будут все равно. Да и с маштабируемостью, возможно, то же.
E>>Т.е. C++ идет лесом, а это мне не нравиться S>Почему же? С++/CLI вполне подойдет.
С++/CLI пусть идет еще более темным лесом!
Лично у меня нет никакого желания с ним связываться.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Sinclair пишет:
> E>Сервера приложений? Или приложения, которые работают под управлением > серверов приложений? > Конечно же собственно серверные приложения. Не важно, под чем они > работают. Вся фишка в том, что современная наука никак не помогает > писать мало-мальски нетривиальные серверные приложения. Например, > реализация банального SMTP-релея представляет собой headache.
Из-за дьявольски сложного семейства почтовых стандартов. Можешь еще
CORBA 3 вспомнить, которую
в полном объеме вообще никто не реализует.
> Даже если использовать RDBMS в качестве storage.
В SMTP-релее как раз хранилище не особо важно. Там и обычной FS хватает.
> Авиабилеты до сих пор приходится продавать через терминальные сервера, > как и тридцать лет назад! Написать нормальный сервис продажи > авиабилетов пока никому не удалось (насколько мне известно).
Плохо, значит, известно. Те же ЖД билеты у нас уже через сравнительно
нормальную систему продают. Да и ничего в таких системах сверхсложного
нет — максимум десятки простых запросов в секунду.
Cyberax пишет: >> Конечно же собственно серверные приложения. Не важно, под чем они >> работают. Вся фишка в том, что современная наука никак не помогает >> писать мало-мальски нетривиальные серверные приложения. Например, >> реализация банального SMTP-релея представляет собой headache. > > Из-за дьявольски сложного семейства почтовых стандартов. Можешь еще
Десяток команд SMTP — где там сложность?
> CORBA 3 вспомнить, которую > в полном объеме вообще никто не реализует. > >> Даже если использовать RDBMS в качестве storage. > > В SMTP-релее как раз хранилище не особо важно. Там и обычной FS хватает. > >> Авиабилеты до сих пор приходится продавать через терминальные сервера, >> как и тридцать лет назад! Написать нормальный сервис продажи >> авиабилетов пока никому не удалось (насколько мне известно). > > Плохо, значит, известно. Те же ЖД билеты у нас уже через сравнительно > нормальную систему продают. Да и ничего в таких системах сверхсложного > нет — максимум десятки простых запросов в секунду.
подозреваю, что раз не могли написать, значит ставилась задача срубить
бабла, а не создать некую систему.
--
Andrei N.Sobchuck
JabberID: andreis@jabber.ru. ICQ UIN: 46466235.
Здравствуйте, eao197, Вы писали:
E>Понятно. Но ты, как я понимаю, больше в сторону .Net смотришь?
В смысле? Я смотрю в сторону турагентств. И оказывается, что если единственная девочка в конторе, прошедшая курсы, ушла на обед, то купить у них билет можно только на рейс Новосибирск-Москва-Новосибирск. Потому как выписка происходит исключительно через зеленый терминал. Ибо построить полноценную клиент-серверную систему в принципе невозможно. И, представляя объемы бабла в этом секторе, не думаю что все из-за лени. Просто правила тарификации для всех компаний свои, и из-за этого нельзя написать модульную эффективную клиент-серверную систему. Поддержка полиморфизма помогла бы перенести ту часть логики, которая происходит в голове у кассира, на сервер. E>А в Java, имхо, в этом направлении активно копают.
Ага. И тем не менее, РСУБД по-прежнему рулят со страшной силой. E>С++/CLI пусть идет еще более темным лесом! E>Лично у меня нет никакого желания с ним связываться.
Ага, как говорил старик Буденный: "Да ну их, эти танки".
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, eao197, Вы писали:
E>>Понятно. Но ты, как я понимаю, больше в сторону .Net смотришь? S>В смысле? Я смотрю в сторону турагентств. И оказывается, что если единственная девочка в конторе, прошедшая курсы, ушла на обед, то купить у них билет можно только на рейс Новосибирск-Москва-Новосибирск. Потому как выписка происходит исключительно через зеленый терминал. Ибо построить полноценную клиент-серверную систему в принципе невозможно. И, представляя объемы бабла в этом секторе, не думаю что все из-за лени. Просто правила тарификации для всех компаний свои, и из-за этого нельзя написать модульную эффективную клиент-серверную систему. Поддержка полиморфизма помогла бы перенести ту часть логики, которая происходит в голове у кассира, на сервер. E>>А в Java, имхо, в этом направлении активно копают. S>Ага. И тем не менее, РСУБД по-прежнему рулят со страшной силой.
Значит возможностей РСУБД в этом направлении с лихвой хватает. И совсем не факт, что супер-пупер ООСУБД (если такое вообще возможно) сделает прорыв в этой области. А Java я упоминул, потому, что там, как мне помниться, в J2EE были работы по прозрачной сериализации Java-объектов в БД и по такому же прозрачному подъему из БД. Кроме того, код Java объектов исполнялся внутри EJB контейнера на серверной стороне. Т.е. для клиента связка EJB+РСУБД выглядит практически так же, как ты хочешь это видеть в ООСУБД.
А что касается задачи, то, имхо, ее сложность и объем (насколько я себе могу представить) не позволяют предположить, что узким местом при ее решении будет СУБД. Имхо, она вполне ляжет на РСУБД + некая логика на стороне сервера приложений.
E>>С++/CLI пусть идет еще более темным лесом! E>>Лично у меня нет никакого желания с ним связываться. S>Ага, как говорил старик Буденный: "Да ну их, эти танки".
Какое-то жуткое засилие дот-нетчиков здесь, нас, C++ программистов, даже понять не хотят!
Я еще готов поверить, что благодоря Mono и DotGNU программы на C# будут переносимыми. Но вот пока C++/CLI не является ANSI C++ стандартом, заморачиваться я на него не хочу. И как показывает топик Будущее С++/CLI
Sinclair пишет:
> E>Понятно. Но ты, как я понимаю, больше в сторону .Net смотришь? > В смысле? Я смотрю в сторону турагентств. И оказывается, что если > единственная девочка в конторе, прошедшая курсы, ушла на обед, то > купить у них билет можно только на рейс > Новосибирск-Москва-Новосибирск. Потому как выписка происходит > исключительно через зеленый терминал. Ибо построить полноценную > клиент-серверную систему в принципе невозможно.
А почему сразу "в принципе"? Особенно когда она уже ЕСТЬ?
> И, представляя объемы бабла в этом секторе, не думаю что все из-за > лени. Просто правила тарификации для всех компаний свои, и из-за этого > нельзя написать модульную эффективную клиент-серверную систему.
Почему? Соединяемся с сервером компании и спрашиваем: "а сколько стоит
билет от ... до ... ?". Мы делали подобную систему, только для биржевых
площадок.
Причем система для этого нужна даже не особо большая — даже во время
пиковых нагрузок не будет больше сотен запросов в секунду.
> Поддержка полиморфизма помогла бы перенести ту часть логики, которая > происходит в голове у кассира, на сервер.
Здравствуйте, Cyberax, Вы писали:
C>eao197 пишет:
>> Значит возможностей РСУБД в этом направлении с лихвой хватает. И >> совсем не факт, что супер-пупер ООСУБД (если такое вообще возможно) >> сделает прорыв в этой области. А Java я упоминул, потому, что там, как >> мне помниться, в J2EE были работы по прозрачной сериализации >> Java-объектов в БД и по такому же прозрачному подъему из БД.
C>Тут разве еще не говорили? http://www.hibernate.org/ — OR-mapping для C>Java. Поддерживает отображение отношений, _полиморфзм_ (он замечательно C>ложится на РСУБД, кстати) и еще кучу фич.
C>И что характерно — все работает и реально используется.
Да я собственно про Java и упоминал, имея в виду Hibernate и EJB контейнеры. У нас несколько команд используют его в связке с JBoss -- вроде никто особенно не жаловался.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Cyberax, Вы писали:
C>Плохо, значит, известно. Те же ЖД билеты у нас уже через сравнительно C>нормальную систему продают.
Это от того, что ЖД билеты продает ровно одна организация, у которой единые тарифы. Модель проста как грабли, поэтому удалось ее автоматизировать при помощи РСУБД.
Причем прикол: для авиабилетов есть веб-сайты. Еще год назад я вообще не мог удаленно узнать, какие поезда ходят между Москвой и Питером, и сколько стоят билеты на них. C>Да и ничего в таких системах сверхсложного C>нет — максимум десятки простых запросов в секунду.
Простые запросы? Ты вообще когда-нибудь авиабилет покупал? Попробуй рассказать, сколько мне будет стоить билет Новосибирск-Франкфурт-Стамбул-Москва-Новосибирск. С учетом скидок и ограничений.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Cyberax, Вы писали: C>Из-за дьявольски сложного семейства почтовых стандартов.
Я же сказал "банального" C>Можешь еще C>CORBA 3 вспомнить, которую C>в полном объеме вообще никто не реализует. C>В SMTP-релее как раз хранилище не особо важно. Там и обычной FS хватает.
Ну-ну. Видел я эти FS-релеи. Самописаный релей (Java + MS SQL) рвал их примерно раз в полсотни по производительности. Не говоря уже об устойчивости к сбоям. Там, где при сбое питания надо очередь руками расчищать
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Cyberax, Вы писали:
C>>Плохо, значит, известно. Те же ЖД билеты у нас уже через сравнительно C>>нормальную систему продают. S>Это от того, что ЖД билеты продает ровно одна организация, у которой единые тарифы. Модель проста как грабли, поэтому удалось ее автоматизировать при помощи РСУБД. S>Причем прикол: для авиабилетов есть веб-сайты. Еще год назад я вообще не мог удаленно узнать, какие поезда ходят между Москвой и Питером, и сколько стоят билеты на них.
Sinclair пишет: > C>В SMTP-релее как раз хранилище не особо важно. Там и обычной FS хватает. > Ну-ну. Видел я эти FS-релеи. Самописаный релей (Java + MS SQL) рвал их > примерно раз в полсотни по производительности. Не говоря уже об > устойчивости к сбоям. Там, где при сбое питания надо очередь руками > расчищать
qmail использует ФС для хранения сообщений. И ничего — один из наиболее
производительных mta.
--
Andrei N.Sobchuck
JabberID: andreis@jabber.ru. ICQ UIN: 46466235.
Sinclair пишет:
> C>Плохо, значит, известно. Те же ЖД билеты у нас уже через сравнительно > C>нормальную систему продают. > Это от того, что ЖД билеты продает ровно одна организация, у которой > единые тарифы. Модель проста как грабли, поэтому удалось ее > автоматизировать при помощи РСУБД.
А что, если модель сложная, то РСУБД автоматически отпадают? )) Могу
ткнуть носом в SAP, в котором сложная модель с 10000 таблиц.
> Причем прикол: для авиабилетов есть веб-сайты. Еще год назад я вообще > не мог удаленно узнать, какие поезда ходят между Москвой и Питером, и > сколько стоят билеты на них.
А это проблемы наших авиакомпаний.
> C>Да и ничего в таких системах сверхсложного > C>нет — максимум десятки простых запросов в секунду. > Простые запросы? Ты вообще когда-нибудь авиабилет покупал? Попробуй > рассказать, сколько мне будет стоить билет > Новосибирск-Франкфурт-Стамбул-Москва-Новосибирск. С учетом скидок и > ограничений.
Считаем маршрут от Новосибирска до Франкфурта (0 запросов — все станции
вполне можно хранить в памяти), затем считаем цену от Новосибирска до
границы (опять же — 0 запросов) и проверяем доступность (1-2 запроса)
свободных мест. Затем просим компанию, ответственную за перевозку от
границы до Франкфурта сделать тоже самое.
И я уж не говорю, что такие сложные заказы едва ли будут 1% от всех заказов.
Sinclair пишет:
> C>Из-за дьявольски сложного семейства почтовых стандартов. > Я же сказал "банального"
Слова "банальный", "корректный" и "email" — несовместимы. Даже банальный
релей должен понимать все форматы адресов, если хочет быть корректным.
> C>Можешь еще > C>CORBA 3 вспомнить, которую > C>в полном объеме вообще никто не реализует. > C>В SMTP-релее как раз хранилище не особо важно. Там и обычной FS хватает. > Ну-ну. Видел я эти FS-релеи. Самописаный релей (Java + MS SQL) рвал их > примерно раз в полсотни по производительности. Не говоря уже об > устойчивости к сбоям. Там, где при сбое питания надо очередь руками > расчищать
А причем здесь ООБД и РСУБД?
ЗЫ: а вообще, рулит QMail. "7 лет и ни одной новой дырки" (c).
Здравствуйте, Cyberax, Вы писали:
C>А что, если модель сложная, то РСУБД автоматически отпадают? )) Могу C>ткнуть носом в SAP, в котором сложная модель с 10000 таблиц.
могу ткнуть носом в правила... но могу сразу забанить, без тыканья. выбор за тобой.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
— сколько программистов надо чтобы заменить сгоревшую лампочку?
— сколько не бери, а лампочку не поменять — проблема аппаратная, программным путем не решается...
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, eao197, Вы писали:
GZ>Джентельмены, с удовольствием прочел ваши мнения, позвольте высказать свое.
Очень интересное мнение.
GZ>[to eao197] GZ>Что касает предложенной тобой заморочки с изменяемыми реализациями. Иногда ее сильно нехватает. С ней, можно было-бы сократить паттерны GoF. Но это палка о двух концах. При этом нужно учитывать, что она не только содержит в себе все недостатки множественного наследования, но и усугубляет их. Если ты попробуешь формализовать процесс создания нового объекта, то ты получишь нехилую кучу требований которые трудно будет выполнять. Если сейчас спросить 10 программистов С++, в каком порядке выполняются конструкторы в объекте с множественным наследованием, то дай бог хоть один уверенно ответит (хотя тут догадаться несложно). Недаром в последних языках используются именно объекты с множественным наследованием интерфейсов без реализаций. Если bvb пользоваться + дополнительно сервисы — то проблемы сами разрешаться.
Если не сложно, GlebZ, об выделенном фрагменте подробнее. Я не очень понял откуда взялось множественное наследование, т.к. я о нем не говорил вроде.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Если не сложно, GlebZ, об выделенном фрагменте подробнее. Я не очень понял откуда взялось множественное наследование, т.к. я о нем не говорил вроде.
Да проблема та же что я и описал. При инициализации объекта, непонятно в каком порядке будут вызываться конструкторы. Но там хоть данные во многом разделены. А тут еще усугубляется тем, что все классы навешаны на один и тот же инстанс. В результате, они должны инициализировать одно и то же состояние, и обязательно в каком-то порядке. В результате — бизнес-логика класса начинает значительно усложняться. Сразу непонятно, вот мы создаем объект. Например мы создаем объект A. Но у нас есть также реализация B, в которой тоже есть некоторая логика создания. То есть, мы обязаны его также поднять. И в каком порядке они должны вызываться? В силу того что при этом состояние на момент выполнение конструктора B очень непонятно, то порядок вызова быть обязан. Ну слово за слово, и пойдет написание требований которые не каждый выучит. Хотя формализация множественного наследования для OODB была, я, например, сейчас и не вспомню что там было написано.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, eao197, Вы писали:
E>>Если не сложно, GlebZ, об выделенном фрагменте подробнее. Я не очень понял откуда взялось множественное наследование, т.к. я о нем не говорил вроде. GZ>Да проблема та же что я и описал. При инициализации объекта, непонятно в каком порядке будут вызываться конструкторы. Но там хоть данные во многом разделены. А тут еще усугубляется тем, что все классы навешаны на один и тот же инстанс. В результате, они должны инициализировать одно и то же состояние, и обязательно в каком-то порядке. В результате — бизнес-логика класса начинает значительно усложняться. Сразу непонятно, вот мы создаем объект. Например мы создаем объект A. Но у нас есть также реализация B, в которой тоже есть некоторая логика создания. То есть, мы обязаны его также поднять. И в каком порядке они должны вызываться? В силу того что при этом состояние на момент выполнение конструктора B очень непонятно, то порядок вызова быть обязан. Ну слово за слово, и пойдет написание требований которые не каждый выучит. Хотя формализация множественного наследования для OODB была, я, например, сейчас и не вспомню что там было написано.
Здесь произошло какое-то недопонимание. Я не говорил про множественное наследование. Я говорил, что при поднятии из БД объект может превратиться в совершенно разные объекты. Например, пусть есть класс surface_t, который в БД представляется типом:
class surface_t
{
material_t * m_material;
geometry_t m_geometry;
};
Этот класс в программе редактирования чертежей имеет вид:
class surface_t
{
protected :
material_t * m_material;
geometry_t m_geometry;
editor_t * m_editor;
public :
...
// Запросить параметры для редактора (цвет, стиль линии, стиль заливки и т.д.)void
properties( editor_properties_t & props ) const;
// Изменить значение указанного параметра (цвета, стиля линии и т.д.)void
change_properties(
const editor_property_t & prop,
editor_undo_redo_t & undo_redo );
// Отобразить объект на чертеже (с учетом группировки, выделения и т.д.)void
paint(
editor_paint_device_t & device,
editor_selection_t & selection ) const;
};
А в программе печати чертежей:
class surface_t
{
protected :
material_t * m_material;
geometry_t m_geometry;
device_properties_t * m_properties;
public :
...
// Отобразить на указанном устройстве.void
draw( paint_device_t & device ) const;
...
};
Т.е. это один и тот же класс, который в программах выглядит по разному. Здесь нет никакого множественного наследования. Речь идет лишь о том, что transient-атрибуты и код методов класса в разных программах реализуется разными библиотеками. Здесь нет никаких проблем с порядком инициализации объектов при извлечении из БД. Фокус в том, что разные in-memory представления объекта превращаются в одинаковое представление объекта в БД.
В чем здесь сложность -- это согласованность состояний одного и того же объекта в разных приложениях. Если классом в разных программах управляет разный код, то обеспечение согласованного состояния persistent атрибутов является основным вопросом.
Когда я в аспирантуре занимался ООСУБД, я только подошел к этому вопросу. Решать его уже было некогда. Но, например, можно предложить что-то вроде идиомы PImpl из C++:
class surface_data_t
{
material_t * m_material;
geometry_t m_geometry;
};
class surface_t
{
surface_data_t m_data;
};
Т.е. типы surface_data_t и surface_t являются сохраняемыми, но только тип surface_t может иметь разные реализации в разных приложениях. Тип surface_data_t должен иметь одинаковую реализацию везде. Т.е., на физическом уровне, есть одна общая библиотека с кодом surface_data_t и множество частных библиотек с кодом surface_t.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, Alexey Rovdo, Вы писали:
GZ>Да уж. Вы практически в точку указали почему OQL нельзя использовать. Вы указали почему — построить нормальный язык очень сложно. Но вы не сказали почему все-таки производители за это не беруться, и почему они пытаются выполнять (даже в новых продуктах) требования ODMG. Мне пока не верится, что это невозможно.
Мне кажется, что производители коммерческих продуктов берутся за все это только по одной причине — желание соответствовать как можно большему числу стандартов. Проприетарные решения не в чести у покупателей, а альтернативы у ODMG пока нет (хотя бурное развитие JDO можно рассматривать как заявку — и этот путь, полагаю, более верен, чем путь ODMG).
GZ>Запросы — это не столько получение некоторого набора объектов, а еще инструмент выполнения некоторых действий на некоторым множеством объектов.
Действительно, групповые операции над данными вообще не предусмотрены никакими спецификациями ООП (по крайней мере я таких не знаю). Как результат, производители вынуждены придумывать свои проприетарные решения. Так, к примеру, в ООСУБД VDS есть некоторые рудиментарные средства, но вот в JDO вроде пока ничего такого ...
Alexey Rovdo пишет:
> Мне кажется, что производители коммерческих продуктов берутся за все > это только по одной причине — желание соответствовать как можно > большему числу стандартов. Проприетарные решения не в чести у > покупателей, а альтернативы у ODMG пока нет (хотя бурное развитие JDO > можно рассматривать как заявку — и этот путь, полагаю, более верен, > чем путь ODMG).
Кхе, кхе. Может стоит посмотреть на RealLife(tm)? В мире Java сейчас
рулит Hibernate для OR-maping'а, JDO не прижился и не особо используется.
Здравствуйте, Cyberax, Вы писали: C>А что, если модель сложная, то РСУБД автоматически отпадают? )) Могу C>ткнуть носом в SAP, в котором сложная модель с 10000 таблиц.
Может быть. С SAP не знаком. Хотя само по себе количество таблиц не всегда определяет меру сложности. >> Простые запросы? Ты вообще когда-нибудь авиабилет покупал? Попробуй >> рассказать, сколько мне будет стоить билет >> Новосибирск-Франкфурт-Стамбул-Москва-Новосибирск. С учетом скидок и >> ограничений. C>Считаем маршрут от Новосибирска до Франкфурта (0 запросов — все станции C>вполне можно хранить в памяти),
Сколько есть таких маршрутов? C>затем считаем цену от Новосибирска до C>границы (опять же — 0 запросов) и проверяем доступность (1-2 запроса) C>свободных мест. Затем просим компанию, ответственную за перевозку от C>границы до Франкфурта сделать тоже самое.
Нда. Похоже, ты никогда на самолете не летал. Открою тебе тайну — нет такой штуки, как "цена от Новосибирска до границы". Во-первых, авиакомпаний — море. Во-вторых, каждая авиакомпания на любой рейс предоставляет от одного до десяти тарифов (в реальности как правило их около пяти). При этом правила применимости тарифа могут включать в себя очень много всяких подробностей, которые я грубияну пересказывать не буду. Раз ты такой умный — сходи и посмотри сам. Вся тонкость в том, что эти правила определяет сама авиакомпания.
В третьих, цена билета Нск-Мск-Франкфурт-Мск-Нск вовсе не равна сумме цен билетов Нск-Мск-Нск и Мск-Франкфурт-Мск.
Тебе никогда не выписывали такой билет, что потом представитель авиакомпании говорил "извините, но в таком сочетании эти скидки не предоставляются"? Это из-за того, что бизнес-логика записана на английском языке, а не на языке программирования. C>И я уж не говорю, что такие сложные заказы едва ли будут 1% от всех заказов.
Да-да. Для бухгалтера "почти никогда" == "не бывает". Для программиста "почти никогда" == "бывает".
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Sinclair пишет:
> C>А что, если модель сложная, то РСУБД автоматически отпадают? )) Могу > C>ткнуть носом в SAP, в котором сложная модель с 10000 таблиц. > Может быть. С SAP не знаком. Хотя само по себе количество таблиц не > всегда определяет меру сложности.
Там сама предметная модель сложная — управление крупным предприятием.
>>> Простые запросы? Ты вообще когда-нибудь авиабилет покупал? Попробуй >>> рассказать, сколько мне будет стоить билет >>> Новосибирск-Франкфурт-Стамбул-Москва-Новосибирск. С учетом скидок и >>> ограничений. > C>Считаем маршрут от Новосибирска до Франкфурта (0 запросов — все станции > C>вполне можно хранить в памяти), > Сколько есть таких маршрутов?
Вряд ли больше, чем роутеров в сети Интернет. А ведь маршрут для
IP-пакета на tier-1 роутерах рассчитывается почти мгновенно.
Пусть во всем мире 100000 аэропортов, тогда количество возможных
маршрутов между ними — 10^10, и это верхняя граница. Это вполне в
пределах даже домашнего компьютера.
> C>затем считаем цену от Новосибирска до > C>границы (опять же — 0 запросов) и проверяем доступность (1-2 запроса) > C>свободных мест. Затем просим компанию, ответственную за перевозку от > C>границы до Франкфурта сделать тоже самое. > Нда. Похоже, ты никогда на самолете не летал. Открою тебе тайну — нет > такой штуки, как "цена от Новосибирска до границы".
Это я сглючил, не заметил слово "авиа" и подумал, что нужны ЖД-билеты. А
весело получается: авиабилет до границы
> Раз ты такой умный — сходи и посмотри сам. Вся тонкость в том, что эти > правила определяет сама авиакомпания. > В третьих, цена билета Нск-Мск-Франкфурт-Мск-Нск вовсе не равна сумме > цен билетов Нск-Мск-Нск и Мск-Франкфурт-Мск.
Ну и что? Когда мы нашли подходящий маршрут, то никто не мешает
переадресовать оценочный запрос серверам конкретных компаний.
> C>И я уж не говорю, что такие сложные заказы едва ли будут 1% от всех > заказов. > Да-да. Для бухгалтера "почти никогда" == "не бывает". Для программиста > "почти никогда" == "бывает".
Для программиста "почти никогда" == "можно не оптимизировать".
Здравствуйте, Cyberax, Вы писали:
C>Кхе, кхе. Может стоит посмотреть на RealLife(tm)? В мире Java сейчас C>рулит Hibernate для OR-maping'а, JDO не прижился и не особо используется.
Hibernate и JDO отличаются не так уж сильно — идеи, стоящие за этим двумя технологиями, очень схожи (отличаются в основном исполнения). Ну а насчет популярности мне выводы делать сложно, но кажется, что какого-то значительного отрыва нет ни у JDO, ни у Hibenate. Во всяком случае "не прижился" — это вы уже загнули.
Здравствуйте, Alexey Rovdo, Вы писали: AR>Из личной практики работы с продуктами Versant я вынес следующее. Запросы нужно использовать при работе с ООСУБД как можно реже. Причин тут несколько.
Совершенно верное замечание. AR>По моим личным впечатлениям декларативные языки запросов вообще не подходят для работы с ООСУБД — они не соответствуют объектной парадигме этих систем, вступая с ней в противоречие. Более понятным и продуктивным здесь может быть процедурный/функциональный подход к написанию запросов.
И с этим я тоже согласен.
Основная проблема произвольного декларативного языка запросов — взаимодействие с объектной моделью. Хорошо, когда все средства построения выражений-предикатов встроены прямо в язык. Когда в эту область вторгаются пользовательские типы и методы, происходит некоторая сложность. Хочется, чтобы язык запросов был вычислительно эквивалентен тому языку, который используется в определении поведения, т.е. кода методов. AR>И, кстати, производители ООСУБД этот подход поддерживают, хотя пока и нельзя сказать, что он сильно развит (далее все гипотетически, конкретных продуктов, работающих подобным образом я не знаю). Т.е. вместо OQL запроса вида: "SELECT * From ObjectClass Where ObjectClass.atrrib = const_Object" мы в ОО-программе пишем что-то вроде "database.GetCollecttion('ObjectClass', constObject.equals)" и получаем результат-коллекцию. Обычно это коллекция ссылок на объекты.
В данный момент я пытаюсь научиться оптимизировать запросы, заданные прямо на языке-носителе в императивном стиле. Предикат описывается не как некоторое функциональное выражение, а прямо как метод на управляемом языке:
AR>Но уже и в этом примере видно, что включение объекта Object в результирующую коллекцию происходит в зависимости от того, какой результат возвратит метод cons_Object.equals(Object). Как оптимизировать такие запросы, если код метода equals может быть очень сложным?
Конвертировать императивный код в функциональное представление. Это можно сделать благодаря реверсируемости управляемого кода. AR>Где отрабатывать код метода?
Ессно на сервере AR>Чтобы создать систему, действительно способную оптимизировать такие запросы, разработчикам ООСУБД еще предстоит много и много потрудиться
Угу. Самое печальное, что заниматься этим совершенно некогда. За науку денег не платят — приходится упражняться урывками.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
C>Вряд ли больше, чем роутеров в сети Интернет. А ведь маршрут для C>IP-пакета на tier-1 роутерах рассчитывается почти мгновенно.
Гм. Насколько мне известно, маршрутизация IP пакетов происходит независимо на каждом шаге. Нет никакого централизованного сервиса построения полного маршрута. C>Пусть во всем мире 100000 аэропортов, тогда количество возможных C>маршрутов между ними — 10^10, и это верхняя граница. Это вполне в C>пределах даже домашнего компьютера. C>Ну и что? Когда мы нашли подходящий маршрут, то никто не мешает C>переадресовать оценочный запрос серверам конкретных компаний.
Ну вот "никто не мешает" почему-то не работает. C>Для программиста "почти никогда" == "можно не оптимизировать".
Дело не в оптимизации. Пойми, что проблема не в низкой эффективности! Проблема в том, что такой системы, как ты рассказываешь, в природе не существует.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Alexey Rovdo пишет:
> C>Кхе, кхе. Может стоит посмотреть на RealLife(tm)? В мире Java сейчас > C>рулит Hibernate для OR-maping'а, JDO не прижился и не особо > используется. > Hibernate и JDO отличаются не так уж сильно — идеи, стоящие за этим > двумя технологиями, очень схожи (отличаются в основном исполнения).
Идеи JDO 1.0 и Hibernate отличаются весьма сильно, JDO — это стандарт
для объектного persistance'а, а Hibernate — именно OR-maping. Поэтому
JDOQL имеет весьма узкую функциональность (Sun как обычно попыталась
сделать самый общий стандарт) по сравнению с HQL. Кроме того, в JDO1.1
не специфицирован сам формат OR-mapping'а. В JDO 2.0 исправлены многие
недостатки, но этот стандарт опоздал на год-два (политика, блин).
> Ну а насчет популярности мне выводы делать сложно, но кажется, что > какого-то значительного отрыва нет ни у JDO, ни у Hibenate. Во всяком > случае "не прижился" — это вы уже загнули.
Sinclair пишет:
> В данный момент я пытаюсь научиться оптимизировать запросы, заданные > прямо на языке-носителе в императивном стиле. Предикат описывается не > как некоторое функциональное выражение, а прямо как метод на > управляемом языке: > >public static bool AcceptVisitor(Person visitor) >{ > return (visitor.Age > 21); >} > >
А сколько времени будет работать такой запрос, если в базе 10000000
человек?
Cyberax пишет: >>public static bool AcceptVisitor(Person visitor) >>{ >> return (visitor.Age > 21); >>} >> >> > А сколько времени будет работать такой запрос, если в базе 10000000 > человек?
В GLORP используется такой подход — вместо реального объекта в
блок-фильтр подсовывается специальный объект который накапливает все
посылаемые ему сообщения. Из этой информации затем и генерируется запрос
к серверу.
--
Andrei N.Sobchuck
JabberID: andreis@jabber.ru. ICQ UIN: 46466235.
Sinclair пишет:
> C>Вряд ли больше, чем роутеров в сети Интернет. А ведь маршрут для > C>IP-пакета на tier-1 роутерах рассчитывается почти мгновенно. > Гм. Насколько мне известно, маршрутизация IP пакетов происходит > независимо на каждом шаге. Нет никакого централизованного сервиса > построения полного маршрута.
Маршрутизация в IP — смешанная. Пакеты идут hop-by-hop маршрутизацией,
но маршруты на каждом хосте рассчитываются со знанием всей топологии сети.
> C>Пусть во всем мире 100000 аэропортов, тогда количество возможных > C>маршрутов между ними — 10^10, и это верхняя граница. Это вполне в > C>пределах даже домашнего компьютера. > C>Ну и что? Когда мы нашли подходящий маршрут, то никто не мешает > C>переадресовать оценочный запрос серверам конкретных компаний. > Ну вот "никто не мешает" почему-то не работает.
Работает. http://www.aviatrans.ru/index.html например.
> C>Для программиста "почти никогда" == "можно не оптимизировать". > Дело не в оптимизации. Пойми, что проблема не в низкой эффективности! > Проблема в том, что такой системы, как ты рассказываешь, в природе не > существует.
Почему нет, когда я своими глазами ее в Канаде ее видел? И главное, я не
знаю причин (даже организационного характера), по которым она невозможна.
Andrei N.Sobchuck wrote: > Cyberax пишет: > >>>public static bool AcceptVisitor(Person visitor) >>>{ >>> return (visitor.Age > 21); >>>} >>> >>> >> >>А сколько времени будет работать такой запрос, если в базе 10000000 >>человек? > > > В GLORP используется такой подход — вместо реального объекта в > блок-фильтр подсовывается специальный объект который накапливает все > посылаемые ему сообщения. Из этой информации затем и генерируется запрос > к серверу. >
Можно построить запрос на основе декомпиляции байт-кода, так сделано в
ReStore. Это покрывает большее количество случаев.
Andrei N.Sobchuck пишет:
>> А сколько времени будет работать такой запрос, если в базе 10000000 >> человек? > В GLORP используется такой подход — вместо реального объекта в > блок-фильтр подсовывается специальный объект который накапливает все > посылаемые ему сообщения. Из этой информации затем и генерируется запрос > к серверу.
И что? Каким образом фильтр поймет, что нужно выполнить выборку по всем
людям с возрастом больше 27 лет?
Сложность все равно O(n) останется, тогда как в RDB в таблице с индексом
по возрасту этот запрос займет O(log n) времени.
Конечно, можно взять в ООБД отсортированную по возрасту коллекцию людей,
и потом уже по ней выполнить поиск, но такой подход будет изморфен RDBшному.
Здравствуйте, _vovin, Вы писали: _>Можно построить запрос на основе декомпиляции байт-кода, так сделано в _>ReStore. Это покрывает большее количество случаев.
Можно ссылочку на ReStore?
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Cyberax, Вы писали: C>А сколько времени будет работать такой запрос, если в базе 10000000 C>человек?
Все зависит от того, как реализованы геттеры свойства Age в потомках класса Person В нормальном случае ~ ln(1000000).
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
_vovin пишет:
>> В GLORP используется такой подход — вместо реального объекта в >> блок-фильтр подсовывается специальный объект который накапливает все >> посылаемые ему сообщения. Из этой информации затем и генерируется запрос >> к серверу. >> > Можно построить запрос на основе декомпиляции байт-кода, так сделано в > ReStore. Это покрывает большее количество случаев.
Это покрывает только тривиальные случаи типа "age>23 and height>180".
Как декомпилировать и осмыслить сложный запрос с join'ами (которые в ИЯ
превратятся в циклы) — мне непонятно.
Cyberax wrote:
> _vovin пишет: > > >>>В GLORP используется такой подход — вместо реального объекта в >>>блок-фильтр подсовывается специальный объект который накапливает все >>>посылаемые ему сообщения. Из этой информации затем и генерируется запрос >>>к серверу. >>> >> >>Можно построить запрос на основе декомпиляции байт-кода, так сделано в >>ReStore. Это покрывает большее количество случаев. > > > Это покрывает только тривиальные случаи типа "age>23 and height>180". > Как декомпилировать и осмыслить сложный запрос с join'ами (которые в ИЯ > превратятся в циклы) — мне непонятно. >
Даже упомянутый случай с GLORP-ом отлично решает эту проблему.
Построенное синтаксическое дерево исходного языка (некоторого
подмножества) отображается на SQL и дальше выполняется обычный запрос.
Это уже пройденный этап. А главная проблема связана с полиморфизмом.
Sinclair wrote:
> Здравствуйте, _vovin, Вы писали: > _>Можно построить запрос на основе декомпиляции байт-кода, так сделано в > _>ReStore. Это покрывает большее количество случаев. > Можно ссылочку на ReStore?
Sinclair пишет:
> From: *Sinclair* </Users/Profile.aspx?uid=5743> rsdn > </search/?group=27> </Users/Private/AddFav.aspx?mid=1111513> > <NewMsg.aspx?gid=27> <NewMsg.aspx?mid=1111513> <?mid=1111513> > <Message.aspx?mid=1111513#1111513> <NewMsg.aspx?mid=1111513&edit=1> > <Private/Self.aspx?mid=1111513> > > Здравствуйте, Cyberax, Вы писали: > C>А сколько времени будет работать такой запрос, если в базе 10000000 > C>человек? > Все зависит от того, как реализованы геттеры свойства Age в потомках > класса Person В нормальном случае ~ ln(1000000).
Причем тут getter'ы? Пусть алгоритм поиска выглядит так:
Schools schools=getAllSchools();
for(int x=0;x<coll.size();x++)
{
Human h=coll.get(x);
if (h.getAge()>27)
{
for (int y=0;y<schools.size();y++)
if (schools.get(x).getStudents().hasObject(h))
resultColl.add(h);
}
}
Для случая RDB такой алгоритм будет работать O(n) без индексов и O(log
n) с индексами.
Если его соптимизировать в его ОО-воплощении, то получится опять тот же
реляционный алгоритм.
GlebZ пишет:
> C>Сложность все равно O(n) останется, тогда как в RDB в таблице с > индексом > C>по возрасту этот запрос займет O(log n) времени. > А кто в ООБД отменил индексы?
Никто.
> C>Конечно, можно взять в ООБД отсортированную по возрасту коллекцию > людей, > C>и потом уже по ней выполнить поиск, но такой подход будет изморфен > RDBшному. > И что в этом плохого? К тому же — индекс можно строить независимо от > вида коллекции.
Тогда непонятно ЧЕМ же OODB отличается от RDB.
Единственное отличие: в OODB идентификатором объекта является OID, в
котором возможно закодировать физическое расположение объекта на диске,
а в RDB идетификтором строки является логический PK. Но это уже слишком
незначительная деталь.
_vovin пишет:
>> Это покрывает только тривиальные случаи типа "age>23 and height>180". >> Как декомпилировать и осмыслить сложный запрос с join'ами (которые в ИЯ >> превратятся в циклы) — мне непонятно. > Даже упомянутый случай с GLORP-ом отлично решает эту проблему. > Построенное синтаксическое дерево исходного языка (некоторого > подмножества) отображается на SQL и дальше выполняется обычный запрос.
В доке на Restore я вижу только простенькие примеры типа "allPersons
select: [ :each | each dateOfBirth year = 1970]." Чего-то сложного я там
не вижу.
Тот же Hinernate с HQL покрывает _значительно_ большую функциональность.
И при этом реально работает.
> Это уже пройденный этап. А главная проблема связана с полиморфизмом.
А в чем с нима проблема? Он замечательно ложится на RDB.
Здравствуйте, Cyberax, Вы писали:
C>Причем тут getter'ы? Пусть алгоритм поиска выглядит так: C>
C>Schools schools=getAllSchools();
C>for(int x=0;x<coll.size();x++)
C>{
C> Human h=coll.get(x);
C> if (h.getAge()>27)
C> {
C> for (int y=0;y<schools.size();y++)
C> if (schools.get(x).getStudents().hasObject(h))
C> resultColl.add(h);
C> }
C>}
C>
Нет уж, пусть он так не выглядит. Во-первых, в нем ошибка (что ясно показывает тупиковость попыток вручную "помочь" серверу выполнить поиск). Во-вторых, никто не собирается пытаться оптимизировать алгоритмы.
От программиста требуется предоставить предикат, а среда обеспечит эффективный поиск объектов, удовлетворяющих этому предикату.
Вот как будет выглядеть предикат на C# 2.0 для твоего примера:
public static bool Predicate(Human h)
{
if (h.Age<=27)
return false;
foreach(School school in Schools)
{
if school.Students.Contains(h)
return true;
}
return false;
}
Естественно, подобный код вряд ли удастся как-то сильно оптимизировать. Но ведь ты на SQL не станешь искать школьников при помощи курсора? Вот и тут — воспользуемся тем фактом, что мы ищем учеников любой школы:
Оптимизатор будет вполне способен увидеть здесь join.
C>Для случая RDB такой алгоритм будет работать O(n) без индексов и O(log C>n) с индексами.
Гм. n — это что?
C>Если его соптимизировать в его ОО-воплощении, то получится опять тот же C>реляционный алгоритм.
Естественно! Цель как раз в том и состоит, чтобы получить алгоритм, близкий к реляционному. Только без ручного затачивания под конкретные реализации, с поддержкой полиморфизма и инкапсуляции. В нормальной системе запрос, который ты хотел написать, будет вообще выглядеть примерно так:
Здравствуйте, Alexey Rovdo, Вы писали:
AR>Мне кажется, что производители коммерческих продуктов берутся за все это только по одной причине — желание соответствовать как можно большему числу стандартов. Проприетарные решения не в чести у покупателей, а альтернативы у ODMG пока нет (хотя бурное развитие JDO можно рассматривать как заявку — и этот путь, полагаю, более верен, чем путь ODMG).
Поэтому и процветают ORM. У них нет понятия о стандартах, у них есть понятия об эффективности. В той степени которой они могут добиться. Тема ODMG уже надоела. Ну неживой он. Прошло столько времени с его создания. Они давно уже распустились. Зачем поддерживать то, чего уже практически нет.
GZ>>Запросы — это не столько получение некоторого набора объектов, а еще инструмент выполнения некоторых действий на некоторым множеством объектов.
AR>Действительно, групповые операции над данными вообще не предусмотрены никакими спецификациями ООП (по крайней мере я таких не знаю). Как результат, производители вынуждены придумывать свои проприетарные решения. Так, к примеру, в ООСУБД VDS есть некоторые рудиментарные средства, но вот в JDO вроде пока ничего такого ...
Знать бы что такое спецификации ООП. Вообще это очень сложная задача. Я бы сказал чрезвычайно сложная. Может потому за нее и не беруться как крупные так и мелкие компании. Но вполне возможная. Я по крайней мере не вижу никаких противопоказаний. SQL — работает же с функциями.
Cyberax wrote:
> _vovin пишет: > > >>>Это покрывает только тривиальные случаи типа "age>23 and height>180". >>>Как декомпилировать и осмыслить сложный запрос с join'ами (которые в ИЯ >>>превратятся в циклы) — мне непонятно. >> >>Даже упомянутый случай с GLORP-ом отлично решает эту проблему. >>Построенное синтаксическое дерево исходного языка (некоторого >>подмножества) отображается на SQL и дальше выполняется обычный запрос. > > > В доке на Restore я вижу только простенькие примеры типа "allPersons > select: [ :each | each dateOfBirth year = 1970]." Чего-то сложного я там > не вижу. > > Тот же Hinernate с HQL покрывает _значительно_ большую функциональность. > И при этом реально работает.
ReStore это простенький инструмент.
Для более сложных вещей есть GLORP и Gemstone.
> > >>Это уже пройденный этап. А главная проблема связана с полиморфизмом. > > > А в чем с нима проблема? Он замечательно ложится на RDB. >
Sinclair пишет:
> C>Тогда непонятно ЧЕМ же OODB отличается от RDB. > Тем, что в RDB нет инкапсуляции, наследования и полиморфизма.
В хранилище ООБД инкапсюляции нет, как и в RDB. Наследование и
полиморфизм замечательно выражаются в RDB в виде объединенных по PK
таблиц (возможно с полями-дискриминаторами).
То есть на практике объектные модели (за исключением самых извращенных)
вполне прилично ложатся в RDB.
Sinclair пишет:
> Вот как будет выглядеть предикат на C# 2.0 для твоего примера: > >public static bool Predicate(Human h) >{ > if (h.Age<=27) > return false; > > foreach(School school in Schools) > { > if school.Students.Contains(h) > return true; > } > return false; >} > >
На HQL это будет выглядеть так: "SELECT human FROM Human human, School
sc WHERE human IN sc.students". Гораздо понятнее, лаконичнее и ложится
совершенно естественным образом на SQL.
Причем в HQL есть group by, сортировки, джойны и т.п. В виде предикатов
это записывается весьма неудобно.
Предикатный поиск, кстати, в Hibernate тоже есть — называется Criteria API.
>public static bool Predicate(Human h) >{ > return (h.Age>27) && (AllStudents.Contains(h)); >} > > > Оптимизатор будет вполне способен увидеть здесь join.
Здравствуйте, Cyberax, Вы писали: C>В хранилище ООБД инкапсюляции нет, как и в RDB. C> Наследование и полиморфизм замечательно выражаются в RDB в виде объединенных по PK C>таблиц (возможно с полями-дискриминаторами).
Существующие решения никакого полиморфизма не предоставляют. C>вполне прилично ложатся в RDB.
Нормальный полиморфизм ты в RDB запаришься складывать. Точнее, внесение малейших изменений потребует перетряхивания значительной части схемы.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Cyberax пишет: > То есть на практике объектные модели (за исключением самых извращенных) > вполне прилично ложатся в RDB.
В репозитории для VW ST лежит пакет позволяющий сохранить любой объект в
БД без написания мапов. Задействовано вроде 6 таблиц (не помню точно).
Думаю для java сделать такое — тоже без проблем.
--
Andrei N.Sobchuck
JabberID: andreis@jabber.ru. ICQ UIN: 46466235.
[скипнуто в знак согласия]
Именно. А теперь представь себе, над одним и тем-же состоянием работают несколько отделов. Любое изменение должно быть состояния должно изменить код каждого из них. Иногда не знаешь, что было изменение от разработчика за соседним компьютером, а тут вообще плохо. Нужна единая прокладка между состоянием и пользователя состояния.
Однако — ты предлагал накладывать несколько реализаций на одно и то же состояние.Re[4]: Объектные базы как они есть
Что меня и возмутило. Объект накладываемый на состояние — священная корова отвечающая за согласованность состояния. Грешно мучить эту корову. Всем придется плохо. А что будет сверху — делегирования, аггрегация, какие-то внешние сервисы... Это уже другой вопрос.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, eao197, Вы писали:
GZ>[скипнуто в знак согласия] GZ>Именно. А теперь представь себе, над одним и тем-же состоянием работают несколько отделов. Любое изменение должно быть состояния должно изменить код каждого из них. Иногда не знаешь, что было изменение от разработчика за соседним компьютером, а тут вообще плохо.
Для контроля изменений коллеги-разработчика применяются системы контроля версий
Мы, например, даже на боевые сервера системы устанавливаем через систему контроля версий
GZ> Нужна единая прокладка между состоянием и пользователя состояния.
А если серьезно, то здесь есть большая проблема, которая требует решения.
Причем для неуправляемого C++ это более серьезный вопрос, чем для управляемых языков/сред. Но и там так же могут быть проблемы. Например, если тянуть код объектов с сервера, то при изменении версии софта на сервере может потребоваться скачивать слишком большой объем кода. Даже если он и закэшируется на клиенте для последующего использования, то первоначальная загрузка может стать очень дорогой (особенно если с кодом объекта потянутся и его зависимости). Кроме того, как быть системам, которые работают в режиме 24x7? Делает клиент очередной запрос на сервер за объектом, а сервер ему и отвечает: дорогой, закачай-ка сначала мегабайт-другой нового кода, а затем я тебе объект отдам. За время этой закачки все транзакции данного клиента тихо по тайм-ауту умирают
Можно сделать как в случае с серверами приложений и тонким клиентом. Клиент только инициирует запрос, который реально выполняется на сервере, рядом с ООСУБД сервером. Но в этом случае обновление версии софта для сервера приложений является простой технической задачей. Даже для систем 24x7. Но такой подход вряд ли возможен для CAD систем.
Еще один подход состоит в том, чтобы сервер понимал версии клиентов. И умел проводить модификацию данных на лету. Т.е. изменилась схема данных на сервере, а объект запросил старый клиент, сервер отдал клиенту объект в старой схеме данных. Получил сервер от старого клиента объект -- преобразовал его к новому виду и сохранил в БД. Такой подход, как мне помниться, у Константина Книжника в Goods был реализован.
GZ>Однако — ты предлагал накладывать несколько реализаций на одно и то же состояние.Re[4]: Объектные базы как они есть
Что меня и возмутило. Объект накладываемый на состояние — священная корова отвечающая за согласованность состояния. Грешно мучить эту корову. Всем придется плохо. А что будет сверху — делегирования, аггрегация, какие-то внешние сервисы... Это уже другой вопрос.
Да, но хотелось бы, чтобы при извлечении объекта из БД не приходилось вручную агрегировать его в какой-то специфический прикладной объект. А то получится как с парсингом данных в XML -- поднимаем из XML DOM-дерево, пробегаем по нему и строим дерево нужных объектов для дальнейшей работы (тоже самое можно и с SAX парсингом делать). Вот этой лишней ручной работы не хотелось бы.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Cyberax, Вы писали: C>>В хранилище ООБД инкапсюляции нет, как и в RDB. C>> Наследование и полиморфизм замечательно выражаются в RDB в виде объединенных по PK C>>таблиц (возможно с полями-дискриминаторами). S>Существующие решения никакого полиморфизма не предоставляют. C>>вполне прилично ложатся в RDB. S>Нормальный полиморфизм ты в RDB запаришься складывать. Точнее, внесение малейших изменений потребует перетряхивания значительной части схемы.
Но ведь полиморфизм относится к коду объектов. Так зачем его в RDB складывать?
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
GZ>> Нужна единая прокладка между состоянием и пользователя состояния.
E>А если серьезно, то здесь есть большая проблема, которая требует решения. E>Причем для неуправляемого C++ это более серьезный вопрос, чем для управляемых языков/сред. Но и там так же могут быть проблемы. Например, если тянуть код объектов с сервера, то при изменении версии софта на сервере может потребоваться скачивать слишком большой объем кода. Даже если он и закэшируется на клиенте для последующего использования, то первоначальная загрузка может стать очень дорогой (особенно если с кодом объекта потянутся и его зависимости). Кроме того, как быть системам, которые работают в режиме 24x7? Делает клиент очередной запрос на сервер за объектом, а сервер ему и отвечает: дорогой, закачай-ка сначала мегабайт-другой нового кода, а затем я тебе объект отдам. За время этой закачки все транзакции данного клиента тихо по тайм-ауту умирают
E>Можно сделать как в случае с серверами приложений и тонким клиентом. Клиент только инициирует запрос, который реально выполняется на сервере, рядом с ООСУБД сервером. Но в этом случае обновление версии софта для сервера приложений является простой технической задачей. Даже для систем 24x7. Но такой подход вряд ли возможен для CAD систем.
А для CAD важен 24x7(с ними не работал)?
E>Еще один подход состоит в том, чтобы сервер понимал версии клиентов. И умел проводить модификацию данных на лету. Т.е. изменилась схема данных на сервере, а объект запросил старый клиент, сервер отдал клиенту объект в старой схеме данных. Получил сервер от старого клиента объект -- преобразовал его к новому виду и сохранил в БД. Такой подход, как мне помниться, у Константина Книжника в Goods был реализован.
Вот именно поэтому есть полиформизм, инкапсуляция и интерфейсы.
Интерфейс — это некоторая соглашение того, что объект умеет делать какой-то набор действий. Напрямую ни схема данных хранилища ООБД, ни сами данные клиенту не доступны. Он может оперировать только интерфейсами. Реализация интерфейсов зависит от других людей. И если эти люди решили, что пользователю можно оставить старую версию интерфейса и сделать новую — то никаких особых проблем не существует.(главное не доводить это до маразма ActiveX). У меня системы именно по такому принципу действуют. При подключении на сервер имен, клиент дает свою версию. Ну и сервер имен отдает те интерфейсы которые могут работать с данной версией клиента.
E>Да, но хотелось бы, чтобы при извлечении объекта из БД не приходилось вручную агрегировать его в какой-то специфический прикладной объект. А то получится как с парсингом данных в XML -- поднимаем из XML DOM-дерево, пробегаем по нему и строим дерево нужных объектов для дальнейшей работы (тоже самое можно и с SAX парсингом делать). Вот этой лишней ручной работы не хотелось бы.
То есть, другими словами. В ООБД хранить не только бизнес-объекты, но и сервисные объекты. То есть, всю бизнес-логику. Которая знает о типах(а лучше, в силу вышеперечисленного, интерфейсы) друг, друга. Если я правильно тебя понял, то я только за. Единственно против чего я категорически против, ни одна сволочь не может добраться к состоянию объекта минуя единую реализацию объекта.
Cyberax пишет:
> На HQL это будет выглядеть так: "SELECT human FROM Human human, School > sc WHERE human IN sc.students". Гораздо понятнее, лаконичнее и ложится > совершенно естественным образом на SQL.
{ты забыл про возраст}
Кстати, мне кажется, что выборка "Human human" и объединение через
"human IN sc.students" выглядит понятно в SQL, но не совсем очевидно в
случае объектов. Ведь нужно что? — у каждой школы, выбрать учеников с
определённым возрастом. Типа, выбрать фамилии пиплов из примера выше:
Schools
collect: [:school | school students surname]
where: [:school | school students age <= 27]
> Причем в HQL есть group by, сортировки, джойны и т.п. В виде предикатов > это записывается весьма неудобно.
Пример выше с сортировкой на GLORP выглядит так:
glorpSession
readManyOf: Human
where: [:each | each school notNIL and: [each age <= 27]]
orderBy: #surname
Совсем не неудобно. Естественно связь Human-2-School нужно задать в
мапе. Если хочется произвольных связей, то тогда получится заметно
многословнее:
glorpSession returningManyOf: Human where: [:each |
each exists: (Query readManyOf: Schools where: [:eachSchool |
(eachSchool students
anySatisfy: [:eachHuman | eachHuman = each)])].
> А если мы сделаем так: > > public static bool Predicate(Human h) > > { > return (sin(h.Age)>0.2763) && (AllStudents.Contains(h)); > }
Функции, которые мапятся на sql — мапим, которые не мапятся — возможны
варианты.
--
Andrei N.Sobchuck
JabberID: andreis@jabber.ru. ICQ UIN: 46466235.
Здравствуйте, GlebZ, Вы писали:
E>>Можно сделать как в случае с серверами приложений и тонким клиентом. Клиент только инициирует запрос, который реально выполняется на сервере, рядом с ООСУБД сервером. Но в этом случае обновление версии софта для сервера приложений является простой технической задачей. Даже для систем 24x7. Но такой подход вряд ли возможен для CAD систем. GZ>А для CAD важен 24x7(с ними не работал)?
Для мелких CAD наверняка не важен. Но, если представить себе какую-нибудь систему автоматизированного проектирования самолетов (с сохранением данных в БД) на которой одновременно работают люди в разных концах земли, то 24x7 может быть необходим.
Когда-то давно я слышал байку, что для какой-то системы проектирования какого-то очередного Боинга была выбрана ООСУБД именно потому, что только она смогла обеспечить необходимую функциональность и производительность. И где размер одного чертежа превышал 4Gb. (Если мне окончательно не отшибает память, то это была то ли ObjectivityDB, то ли ObjectStore. Или Versant).
E>>Еще один подход состоит в том, чтобы сервер понимал версии клиентов. И умел проводить модификацию данных на лету. Т.е. изменилась схема данных на сервере, а объект запросил старый клиент, сервер отдал клиенту объект в старой схеме данных. Получил сервер от старого клиента объект -- преобразовал его к новому виду и сохранил в БД. Такой подход, как мне помниться, у Константина Книжника в Goods был реализован. GZ>Вот именно поэтому есть полиформизм, инкапсуляция и интерфейсы. GZ>Интерфейс — это некоторая соглашение того, что объект умеет делать какой-то набор действий. Напрямую ни схема данных хранилища ООБД, ни сами данные клиенту не доступны. Он может оперировать только интерфейсами. Реализация интерфейсов зависит от других людей. И если эти люди решили, что пользователю можно оставить старую версию интерфейса и сделать новую — то никаких особых проблем не существует.(главное не доводить это до маразма ActiveX). У меня системы именно по такому принципу действуют. При подключении на сервер имен, клиент дает свою версию. Ну и сервер имен отдает те интерфейсы которые могут работать с данной версией клиента.
И это правильно.
E>>Да, но хотелось бы, чтобы при извлечении объекта из БД не приходилось вручную агрегировать его в какой-то специфический прикладной объект. А то получится как с парсингом данных в XML -- поднимаем из XML DOM-дерево, пробегаем по нему и строим дерево нужных объектов для дальнейшей работы (тоже самое можно и с SAX парсингом делать). Вот этой лишней ручной работы не хотелось бы. GZ>То есть, другими словами. В ООБД хранить не только бизнес-объекты, но и сервисные объекты. То есть, всю бизнес-логику. Которая знает о типах(а лучше, в силу вышеперечисленного, интерфейсы) друг, друга. Если я правильно тебя понял, то я только за. Единственно против чего я категорически против, ни одна сволочь не может добраться к состоянию объекта минуя единую реализацию объекта.
Да, выходит, что ты правильно меня понял (точнее, я в конце-концов смог внятно изложить свою позицию).
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, GlebZ, Вы писали:
GZ>Знать бы что такое спецификации ООП. Вообще это очень сложная задача. Я бы сказал чрезвычайно сложная. Может потому за нее и не беруться как крупные так и мелкие компании. Но вполне возможная. Я по крайней мере не вижу никаких противопоказаний. SQL — работает же с функциями.
Лень заставляет говорить меня следующие вещи:
я не думаю, что нужно реализовывать подмножество какого-то там языка. если уж язык управляемый, то стоит использовать именно его самого, а не имитацию. существуют permissions на код. код должен исполняться на сервере. известна проблема полиморфности. поднимать объекты из базы при выборке — страшные тормоза. значит нужно хранить объекты в памяти.
я тоже думаю, что OODB обязана быть сервером приложений. для этого нужно реализовать транзакции на уровне оперативной памяти. т.к. всё очень лень, мне кажется лучше дописать mono'вский jitter для этих вещей.
IMHO одни C# с VB.NET сразу покроют процентов 10 пользователей базами данных.
GZ>С уважением, Gleb.
хорошо написано, осталось вспомнить, откуда вообще есть пошли СУБД. Именно оттуда, что внешняя память имеет ограничено-произвольный доступ, скорее даже местами последовательный...
СУБД — это ср-во хранения больших объемов данных на ВНЕШНЕМ носителе таким образом, чтобы обеспечивать быстое извлечение необходимых данных в оперативную память. Для организации этого мы используем ЛОГИЧЕСКОЕ проедставление данных, ключи, индексы (уменьшающие размер ВНЕШНЕЙ памяти, требуемый для поиска) и пр.
Берем ООП. В "живой" ООП программе в памяти "нанизаны" километры кружевов и макраме из ФИЗИЧЕСКИХ связей объектов опять же произвольной ФИЗИЧЕСКОЙ структуры. Соответственно, для эффективной работы ООП-ориентированных программ нужна память с абсолютно произвольным доступом.
Вполне возможно, что в какой-то момент времени в выч. системах оперативная память будет:
а) обладать персистентностью (типа flash).
б) быть "необходимого" размера.
Тогда ООП-хранилища и "покажут" этой реляционке, с ее суррогатными ключами и индексами.
------------
Как неплохую полумеру, я бы рассмотрел пока надежный движок РСУБД, который можно было бы ембеддить прямо в свою программу. Причем, открыть доступ к данным не только посредством SQL-запросов, но и для обычного алгоритмического сканирования и обработки. Да, тут уже за эффективность "плана" запроса будет отвечать сам программист, однако при наличии очень большого радиуса кривизны рук, можно получить весьма эффективную систему, сочетающую все, что нужно сочетать...
я бы не отказался в коде писать нечто (некий С++ — подобный язык, например):
Здравствуйте, vdimas, Вы писали:
V>СУБД — это ср-во хранения больших объемов данных на ВНЕШНЕМ носителе таким образом, чтобы обеспечивать быстое извлечение необходимых данных в оперативную память. Для организации этого мы используем ЛОГИЧЕСКОЕ проедставление данных, ключи, индексы (уменьшающие размер ВНЕШНЕЙ памяти, требуемый для поиска) и пр.
Как раз физическая организация логических данных на диске + индексы серьезно УВЕЛИЧИВАЮТ объем внешней памяти, необходимый для хранения данных
V>------------ V>Как неплохую полумеру, я бы рассмотрел пока надежный движок РСУБД, который можно было бы ембеддить прямо в свою программу. Причем, открыть доступ к данным не только посредством SQL-запросов, но и для обычного алгоритмического сканирования и обработки. Да, тут уже за эффективность "плана" запроса будет отвечать сам программист, однако при наличии очень большого радиуса кривизны рук, можно получить весьма эффективную систему, сочетающую все, что нужно сочетать...
По-моему, есть такие готовые ООСУБД.
V>я бы не отказался в коде писать нечто (некий С++ — подобный язык, например):
Что-то похожее на то, что ты описал, поддерживали ООСУБД, в которых была поддержка C++. Насколько мне помниться, похожие возможности предоставлял POET (в последствии FastObjects).
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
V>>------------ V>>Как неплохую полумеру, я бы рассмотрел пока надежный движок РСУБД, который можно было бы ембеддить прямо в свою программу. Причем, открыть доступ к данным не только посредством SQL-запросов, но и для обычного алгоритмического сканирования и обработки. Да, тут уже за эффективность "плана" запроса будет отвечать сам программист, однако при наличии очень большого радиуса кривизны рук, можно получить весьма эффективную систему, сочетающую все, что нужно сочетать...
E>По-моему, есть такие готовые ООСУБД.
V>>я бы не отказался в коде писать нечто (некий С++ — подобный язык, например):
E>Что-то похожее на то, что ты описал, поддерживали ООСУБД, в которых была поддержка C++. Насколько мне помниться, похожие возможности предоставлял POET (в последствии FastObjects).
Действительно очень похоже на FastObjects — особенно на FastObjects .NET (там тоже все модификаторы прямо в коде описания классов). Да и названные вами характеристики (ембеддить прямо в свою программу) — это тоже именно про FastObjects.
Здравствуйте, Cyberax, Вы писали:
C>eao197 пишет:
>> Значит возможностей РСУБД в этом направлении с лихвой хватает. И >> совсем не факт, что супер-пупер ООСУБД (если такое вообще возможно) >> сделает прорыв в этой области. А Java я упоминул, потому, что там, как >> мне помниться, в J2EE были работы по прозрачной сериализации >> Java-объектов в БД и по такому же прозрачному подъему из БД.
C>Тут разве еще не говорили? http://www.hibernate.org/ — OR-mapping для C>Java. Поддерживает отображение отношений, _полиморфзм_ (он замечательно C>ложится на РСУБД, кстати) и еще кучу фич.
C>И что характерно — все работает и реально используется.
AR>Во-первых, чувствуется слабость оптимизаторов (особенно это касается FastObjects). Как результат приходтся более внимательно писать приложение и часть работы по оптимизации выполнять самому, не надеясь на то, что оптимизатор выберет наилучшее решение. Но главное — нужно так строить сами объектные структуры, чтобы заменить запросы прямой навигацией. Ко всему и ограниченность имеющегося языка запросов (FastObjects) не способствует тому, чтобы было желание запросы активно использовать. Как ни странно, указанный подход вполне срабатывает. ООСУБД предлагают достаточно инструментов, которые реально замещают запросы во многих ситуациях.
в ответ на это можно привести сообщение с SQL.ru:
Как-то в поледнее время гложит мысль, что cost-based оптимизатор — не обязательно есть польза. Просто у нас тут баальшая база, ну и куча запросов естественно. Мого времени тратится на переписывание уже давно написанных запросов. При этом цикл примерно сделующий:
пишется запрос,
оптимизируется
работает.
на сервере естественно меняется старистика в связи с изменением данных
приходит время серверу переоптимизировать запрос (например, в связи с перегрузкой сервера).
в новых условиях запрос оптимизируется по-другому и уже не работает нормально (данные большие, шаг влево, шаг вправо — запрос практ. виснет навсегда)
goto п. 1 (оптимизация).
Хорошо еще , если из этого цикла есть выход по условию, являющийся естественно полной фиксацией плана запроса в виде хинтов , forceplan ("прибивает гвоздями" порядок обработки таблиц в запросе, если кто не знает) и прочей лабуды (если она вообще есть у сервера, вон говорят в DB2 вообще нет хинтов).
Вот и задумываюсь я. Вроде бы как cost-based оптимизатор — стандарт для Enterprise-систем. И вижу я впереди полный беспросвет в виде вышеприведенного бесконечного цикла. Выхода нету. Все.
GZ>Что касается билетов. Была некоторая рекламная статья, от какой-то OODB. Какая не помню (давно было), но прикольно то что они как раз и обналичивали кассы авиабилетов. Вобщем замена Oracle на OODB дало очень большой прирост в производительности. Но чего-то сразу ее не нашел. Так что, верьте на слово.
Простите за англ язык, вот, напрмер, такая информация:
Versant in Transportation: Air France
Air France selected Versant and the Sabre Availability Processor (SAP) in 1997 to deploy a next generation yield management application to optimize global revenue by 1-2%
Versant’s object database management system was chosen because it could model a complex array of worldwide fares, inventory and schedules and calculate costs on an individual seat level, critical requirements that a relational database could not handle
Using Versant and SAP, Air France continues to generate incremental revenue streams while guaranteeing response times of under 2 seconds
“The Versant and SAP based solution extends the life of our mainframe system by processing transactions off the mainframe. The application is even faster than we expected and will generate returns that impact our bottom line.”
Pierre Gandois
Air France, Yield Management Project Manager
Versant in Transportation: British Airways
Versant ODBMS is the core database for BA’s Yield Management System used to maximize revenues. Delivered on time and within budget
Why BA selected Versant
Performance: Versant proved to be the best performing DB (40X) in benchmarks against RDBs and other ODBs
Scalability: Proven scalability of data volumes, transaction rates. 1500 flights per day vs 50 for an RDB.
24x7 capability: High availability support including online DB admin and online schema evolution, HA Backup.
Support & professional services: Highly capable and responsive support staff
BZ>Performance: Versant proved to be the best performing DB (40X) in benchmarks against RDBs and other ODBs
Да. Очень похоже что именно это я и видел. Меня просто поразила данная цифра, потому и запомнил.
Здравствуйте, BaZa, Вы писали:
BZ>Вот и задумываюсь я. Вроде бы как cost-based оптимизатор — стандарт для Enterprise-систем. И вижу я впереди полный беспросвет в виде вышеприведенного бесконечного цикла. Выхода нету. Все.
В большей степени — это проблема больше надумана. Я ни разу в жизни в рабочих проектах не использовал настройки оптимизатора для полноценных баз типа MS SQL 2000 или Oracle. Эти базы имеют достаточно хороший оптимизатор. Изменение плана выполнения в базах, чрезвычайно маловероятная вещь. Хотя и для этого много чего придумано. А управление планом выполнения через добавление индексов или темповых таблиц — считаю более правильным методом.
GZ>Итого, при нормальной реализации языка, можно вполне говорить о том, что ООБД — уже готовый сервер приложений.
Можно обсудить тогда реализации OQL. Я лично работал только с одной — VQL (Versant Query Language). Если кому инетересно могу рассказать.
Кстати, VDS имеет два уровня возможностей построения запросов:
VQL: объектные запросы выполняются на стороне сервера, с поддержкой навигации, курсоров и параллельных запросов...........
SQL: с поддержкой ODBC и JDBC, которая позволяет использовать инструменты построения отчетов для генерирования нерегламентированные запросов к VDS. (этот инструмент дает возможность использования ХП)
Здравствуйте, BaZa, Вы писали:
GZ>>Что касается билетов. Была некоторая рекламная статья, от какой-то OODB. Какая не помню (давно было), но прикольно то что они как раз и обналичивали кассы авиабилетов. Вобщем замена Oracle на OODB дало очень большой прирост в производительности. Но чего-то сразу ее не нашел. Так что, верьте на слово.
BZ>Вот например, такая информация:
BZ>Versant in Transportation: Air France BZ>Versant in Transportation: British Airways
На эту же тему, но уже относительно ObjectStore:
ANA Airlines
Major Japanese airline All Nippon Airways Co., Ltd. (ANA) advocates the principle that "customers come first." To instantiate that philosophy, ANA chose ObjectStore to integrate its disparate customer databases into a single customer system that drives the ANA Mileage Club, its frequent flier program. As a result, the program participation has doubled within three years. Read the case study (PDF).
Delta Airlines
ObjectStore provides crucial data services to key DNS applications, helping to track in-flight aircraft positions by capturing and correlating data received from both Delta systems and FAA sources. Additionally, data caching services from ObjectStore are used to enable flight controllers to quickly assemble views of the overall system status, delivering responsiveness that simply was not available from its relational data stores.
The ObjectStore ODBMS is used in SouthWest Airline's Home Gate to provide self service to travelers through the Internet. This allows them to plan trips and purchase tickets on SouthWest Airlines.
Здравствуйте, Poudy, Вы писали:
P>Лень заставляет говорить меня следующие вещи:
Моя лень заставляет меня молчать, желательно, в постели с бокалом коньяка(ну и все остальное).
P>я не думаю, что нужно реализовывать подмножество какого-то там языка. если уж язык управляемый, то стоит использовать именно его самого, а не имитацию. существуют permissions на код. код должен исполняться на сервере. известна проблема полиморфности. поднимать объекты из базы при выборке — страшные тормоза. значит нужно хранить объекты в памяти.
Что касается проблемы полиморфности, то сейчас уже много вещей можно делать. Например, тем чем занимается Sinclair.
В остальном — Объектные базы как сервера приложений
P>я тоже думаю, что OODB обязана быть сервером приложений. для этого нужно реализовать транзакции на уровне оперативной памяти. т.к. всё очень лень, мне кажется лучше дописать mono'вский jitter для этих вещей.
Да на здоровье, используй MTS. Он тоже менеджер транзакции в оперативной памяти. Но по моему ты плохо представляешь полноценный механизм транзакций. Как только мы наступаем на конкурирующие транзакции, то в алгоритме тривиальность пропадает. И начинается куча проблем которые приходится решать в зависимости от бизнес-логики. И механизмов гарантирующих любую транзакцию (если он не построен на конкретной бизнес-логике), я не видел.
Здравствуйте, vdimas, Вы писали:
V>СУБД — это ср-во хранения больших объемов данных на ВНЕШНЕМ носителе таким образом, чтобы обеспечивать быстое извлечение необходимых данных в оперативную память. Для организации этого мы используем ЛОГИЧЕСКОЕ проедставление данных, ключи, индексы (уменьшающие размер ВНЕШНЕЙ памяти, требуемый для поиска) и пр.
Ошибка. Индексы предназначены не только для увеличения hit-ratio. Индексы — это способ убыстрения доступа к данным со сложностью O(NlogN) или O(1) для хешей. Это говорит о обязательности индекса при наличии большого количества объектов. А БД работает именно с большим кол-вом объектов.
V>Вполне возможно, что в какой-то момент времени в выч. системах оперативная память будет: V>а) обладать персистентностью (типа flash). V>б) быть "необходимого" размера.
Хорошо бы.
V>------------ V>Как неплохую полумеру, я бы рассмотрел пока надежный движок РСУБД, который можно было бы ембеддить прямо в свою программу. Причем, открыть доступ к данным не только посредством SQL-запросов, но и для обычного алгоритмического сканирования и обработки. Да, тут уже за эффективность "плана" запроса будет отвечать сам программист, однако при наличии очень большого радиуса кривизны рук, можно получить весьма эффективную систему, сочетающую все, что нужно сочетать...
Почти OODB. Только за план запроса отвечает автоматика.
Здравствуйте, Sinclair, Вы писали:
E>>Например, если БД содержит огромное количество структурированной измерительной информации (Objectivity в CERN, как мне помниться, как раз для этого и применялась), то большинство объектов в ней вообще не нуждаются в методах. S>Как, впрочем, и в объектах. Я плохо знаком с тем, что хранит CERN. Подозреваю, что у них с теми объектами, которые мы привыкли видеть в ООП, общего мало или вообще ничего. S>Кстати, я встречал такое мнение, что ООБД — это "способ придания семантики данным типа BLOB".
Это и есть самая большая база данных в мире (уже польше петабайта). Работает на базе ООСУБД Objectivity/DB, которая довольно популярна в научной среде.
Здравствуйте, Alexey Rovdo, Вы писали:
AR>Здравствуйте, eao197, Вы писали:
E>>Вот, нашел ссылку на проект, в котором используется одна из самых больших в мире объектных БД: http://www.slac.stanford.edu/BFROOT/www/Public/Computing/Databases/index.shtml
AR>Это и есть самая большая база данных в мире (уже польше петабайта). Работает на базе ООСУБД Objectivity/DB, которая довольно популярна в научной среде.
Да я знаю
Просто ссылку когда-то потерял, а сейчас решил, что в тему будет, и нашел вновь.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, GlebZ, Вы писали:
GZ>Что касается проблемы полиморфности, то сейчас уже много вещей можно делать. Например, тем чем занимается Sinclair. GZ>В остальном — Объектные базы как сервера приложений
IMHO, генерить такой SQL, как делает Sinclair — сложная и странная задача. Допустим, были бы у него исходники написанного им же RDBMS сервера. Неужели он стал бы генерировать SQL? Сейчас я смотрю на это как на попытку транслировать, допустим, C# в AST-tree, чтобы оптимизировать его для работы с ... данными на диске, грубо говоря.
P>>я тоже думаю, что OODB обязана быть сервером приложений. для этого нужно реализовать транзакции на уровне оперативной памяти. т.к. всё очень лень, мне кажется лучше дописать mono'вский jitter для этих вещей. GZ>Да на здоровье, используй MTS. Он тоже менеджер транзакции в оперативной памяти. Но по моему ты плохо представляешь полноценный механизм транзакций. Как только мы наступаем на конкурирующие транзакции, то в алгоритме тривиальность пропадает. И начинается куча проблем которые приходится решать в зависимости от бизнес-логики. И механизмов гарантирующих любую транзакцию (если он не построен на конкретной бизнес-логике), я не видел.
Да и не только MTS. Но я не понимаю уникальности проблемы. Предположим есть MTS, который складывает каждое обращение с полю объекта в базу данных, и читает всегда оттуда же. Мне кажется, что все проблемы с изоляцией останутся.
Здравствуйте, Poudy, Вы писали:
P>Здравствуйте, GlebZ, Вы писали:
GZ>>Что касается проблемы полиморфности, то сейчас уже много вещей можно делать. Например, тем чем занимается Sinclair. GZ>>В остальном — Объектные базы как сервера приложений
P>IMHO, генерить такой SQL, как делает Sinclair — сложная и странная задача. Допустим, были бы у него исходники написанного им же RDBMS сервера. Неужели он стал бы генерировать SQL? Сейчас я смотрю на это как на попытку транслировать, допустим, C# в AST-tree, чтобы оптимизировать его для работы с ... данными на диске, грубо говоря.
Тут я думаю он сам ответит.
GZ>>Да на здоровье, используй MTS. Он тоже менеджер транзакции в оперативной памяти. Но по моему ты плохо представляешь полноценный механизм транзакций. Как только мы наступаем на конкурирующие транзакции, то в алгоритме тривиальность пропадает. И начинается куча проблем которые приходится решать в зависимости от бизнес-логики. И механизмов гарантирующих любую транзакцию (если он не построен на конкретной бизнес-логике), я не видел. P>Да и не только MTS. Но я не понимаю уникальности проблемы. Предположим есть MTS, который складывает каждое обращение с полю объекта в базу данных, и читает всегда оттуда же. Мне кажется, что все проблемы с изоляцией останутся.
Я наверно неправильно выразился. Я хотел противопоставить MTS и реальные проблемы изоляции что было тобой сразу подмечено.
GlebZ wrote:
> C>В хранилище ООБД инкапсюляции нет, как и в RDB. > В хранилище нет. В ООDB да. В хранилище ООБД только состояние объектов.
Ну так и рассматривайте RDB как _хранилище_ информации, с которой вполне
можно работать в ООП-стиле.
> C>Наследование и > C>полиморфизм замечательно выражаются в RDB в виде объединенных по PK > C>таблиц (возможно с полями-дискриминаторами). > Это всего лишь один из самых простых и самых неэффективных способов > маппирования объектов в RDBMS.
В ООБД оно представляется точно таким же образом
> C>То есть на практике объектные модели (за исключением самых извращенных) > C>вполне прилично ложатся в RDB. > Ну почти да. Только для этого нужно очень много дописать. И учитывая > удаленность хранилища и самой системы эффективности достойной ООДБ ты > точно не получишь
Ничего особо не нужно на практике. Берется Hibernate, пишется
mapping-файл (этот шаг можно пропустить и сгенерировать его из описания
БД или из Java-классов). Удаленность БД, конечно, сказывается, но далеко
не фатально — в реальности все работает более чем удовлетворительно.
Sinclair wrote:
> C>В хранилище ООБД инкапсюляции нет, как и в RDB. > C> Наследование и полиморфизм замечательно выражаются в RDB в виде > объединенных по PK > C>таблиц (возможно с полями-дискриминаторами). > Существующие решения никакого полиморфизма не предоставляют.
Кроме того, рекомендую прочитать документацию по Hibernate, чтобы потом
не натыкаться на такие "несуществующие" решения.
> C>вполне прилично ложатся в RDB. > Нормальный полиморфизм ты в RDB запаришься складывать. Точнее, > внесение малейших изменений потребует перетряхивания значительной > части схемы.
Я _уже_ год _на_ _практике_ работаю с полиморфными объектами в БД.
Никаких особых проблем.
Andrei N.Sobchuck wrote:
>> На HQL это будет выглядеть так: "SELECT human FROM Human human, School >> sc WHERE human IN sc.students". Гораздо понятнее, лаконичнее и ложится >> совершенно естественным образом на SQL. > {ты забыл про возраст}
Спасибо, щас исправим...
"SELECT human FROM Human human, School sc WHERE (human IN sc.students)
AND (human.age <= 27)"
> Кстати, мне кажется, что выборка "Human human" и объединение через > "human IN sc.students" выглядит понятно в SQL, но не совсем очевидно в > случае объектов. Ведь нужно что? — у каждой школы, выбрать учеников с > определённым возрастом.
Да, пример получился искусственным.
> Пример выше с сортировкой на GLORP выглядит так: > >glorpSession > readManyOf: Human > where: [:each | each school notNIL and: [each age <= 27]] > orderBy: #surname > > > Совсем не неудобно. Естественно связь Human-2-School нужно задать в > мапе.
BaZa wrote:
> C>Тут разве еще не говорили? http://www.hibernate.org/ — OR-mapping для > C>Java. Поддерживает отображение отношений, _полиморфзм_ (он замечательно > C>ложится на РСУБД, кстати) и еще кучу фич. > C>И что характерно — все работает и реально используется. > Посмотрите этот бенчмарк: > http://www.middlewareresearch.com/torpedo/results.jsp > Так что, как видно из результатов, Hibernate не так уж и хорош...
А я могу придумать бенчмарк, где наша внутренняя ORM будет выигрывать.
TORPEDO — это сравнение по скорости, а практика показывает, что 2-3%
оверхеда от Hibernate практически никогда не заметны.
Здравствуйте, Cyberax, Вы писали:
C>Ну так и рассматривайте RDB как _хранилище_ информации, с которой вполне C>можно работать в ООП-стиле.
И строить запросы по состоянию, то бишь нарушать инкапсуляцию? Вообще, если говорить по правде, то я отнюдь не против ORM. Но то, что ООБД на несколько порядков эффективнее выполняют эту задачу — это правда.
>> C>Наследование и >> C>полиморфизм замечательно выражаются в RDB в виде объединенных по PK >> C>таблиц (возможно с полями-дискриминаторами). >> Это всего лишь один из самых простых и самых неэффективных способов >> маппирования объектов в RDBMS.
C>В ООБД оно представляется точно таким же образом
Не есть правда. Ты сам ложишь ссылки на Hibernate, ну и посмотри в возможные значения метаданных. Там только одно плохо. Смешивать различные виды связывания parent-child для типа — нельзя.
C>Ничего особо не нужно на практике. Берется Hibernate, пишется C>mapping-файл (этот шаг можно пропустить и сгенерировать его из описания C>БД или из Java-классов). Удаленность БД, конечно, сказывается, но далеко C>не фатально — в реальности все работает более чем удовлетворительно.
Удовлетворительно для определенного класса задач. Во других классах задач приходится переходить на чистый SQL без объектной схемы. Потому как фатально получается. Реляционки не очень приспособлены к навигационному доступу ни в плане межсерверных вызовов, ни в плане быстрого выполнения запроса (обработка SQL — тяжелая задача и также требуется быстрая прямая адресация объекта). Поэтому и говорю об эффективности.
Еще проблемка для размышления. Синхронизация объектной модели и запросов — проблема не решена.
Например(пишу примерно).
//получаем объект
select * from ldobj where name='AAA';
....
obj.Name='BBB';
....
select * from ldobj where name='BBB';
а такого объекта нет. Потому как не сохранен и существует только в кэш.
Здравствуйте, Cyberax, Вы писали:
C>А я могу придумать бенчмарк, где наша внутренняя ORM будет выигрывать. C>TORPEDO — это сравнение по скорости, а практика показывает, что 2-3% C>оверхеда от Hibernate практически никогда не заметны.
Прочитайте внимательнее, что такое TORPEDO — я бы никак не назвал это сравнением по скорости. Скорее это сравнение по эффективности, а скорость трудно адекватно измерить, поскольку она сильно зависит от конфигураций железа (и для разных продуктов оптимальны разные конфигурации).
BaZa wrote:
> C>А я могу придумать бенчмарк, где наша внутренняя ORM будет выигрывать. > C>TORPEDO — это сравнение по скорости, а практика показывает, что 2-3% > C>оверхеда от Hibernate практически никогда не заметны. > Дело в том, что я лишь хотел показать, что Hibernate это не панацея, > как привыкли думать у нас, в России. > А насчет бенчмарка, то я тоже могу придумать такую ситуацию, в которой > наша "proprietary O/R Mapping Tool" сделает все остальные...
Не панацея, конечно, но ООЧЕНЬ близко к этому
> Но как насчет таких пунктов как Scalable, Flexible (и даже Modular и > EasyToUse)?
Modular — на "4", EasyToUse — "5", Flexible — "4", Scalable — "5".
> За удовлетворение всем таким требованиям и можно поступится > быстродействием в конкретной задаче, и получить универсальный > инструмент...
Я работал немного с Versant в свое время — Hibernate его (по моим
ощущениям) намного превосходит в удобстве.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, vdimas, Вы писали:
V>>СУБД — это ср-во хранения больших объемов данных на ВНЕШНЕМ носителе таким образом, чтобы обеспечивать быстое извлечение необходимых данных в оперативную память. Для организации этого мы используем ЛОГИЧЕСКОЕ проедставление данных, ключи, индексы (уменьшающие размер ВНЕШНЕЙ памяти, требуемый для поиска) и пр. GZ>Ошибка. Индексы предназначены не только для увеличения hit-ratio. Индексы — это способ убыстрения доступа к данным со сложностью O(NlogN) или O(1) для хешей. Это говорит о обязательности индекса при наличии большого количества объектов. А БД работает именно с большим кол-вом объектов.
ну и где мое высказывание противоречит твоему замечанию
могу еще пройтись по твоим индексам со сложностью поиска O(NlogN) для физического хранения... какой здравомыслящий человек будет использовать последовательный индекс при хранении в памяти больших наборов данных? кеши рулят...
Здравствуйте, Cyberax, Вы писали: C>Кроме того, рекомендую прочитать документацию по Hibernate, чтобы потом C>не натыкаться на такие "несуществующие" решения.
Нда... Если обзывать "полиморфизмом" возможность возврата всех наследников класса одним запросом, то, конечно, все будет здорово. C>Я _уже_ год _на_ _практике_ работаю с полиморфными объектами в БД. C>Никаких особых проблем.
Круто. И как там в Hibernate с поддержкой запросов, в которых предикаты полиморфны? Нормально? Или там в предикатах тоже методы вызывать запрещено?
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, GlebZ, Вы писали:
V>>ну и где мое высказывание противоречит твоему замечанию GZ>Это дополнение которое перечеркивают твое следующее высказывание GZ>
GZ>Тогда ООП-хранилища и "покажут" этой реляционке, с ее суррогатными ключами и индексами.
Не смотришь в корень или я недостаточно выразил свою мысль. Мне, например, непонятно назначение индекса по суррогатному (логическому) ключу, если мне не нужен сам суррогатный ключ. ForeignKey иже с ним.
V>>могу еще пройтись по твоим индексам со сложностью поиска O(NlogN) для физического хранения... какой здравомыслящий человек будет использовать последовательный индекс при хранении в памяти больших наборов данных? кеши рулят... GZ>Я. Может я и не здравомыслящий, но для алгоритмов с большим набором данных строить B+ индекс(или хотя бы чистый бинарник) — первое дело. Иметь одновременно сортированный список с быстрым доступом и вставкой, с возможностью адаптирования доступа алгоритмов по некоторому range — не самое плохое предприятие.
А я намекал как раз на хеш-способ организации этих самых индексов в ФИЗИЧЕСКОЙ памяти. Ибо как раз они дают быстрый доступ и вставку. Немного непонятно, как ты собрался быстро вставлять в B-индекс? Если я не ошибаюсь, то надо двигать в памяти все миллионы вхождений индексируемого значения?
GZ>PS: только не надо намекать на хеши Net. Оссобенно в связи с их тактикой пересчета хеша. Для больших данных — это нереальный алгоритм.
Ну да, они там размер основной таблицы хеша пересчитывают при росте количества данных. Однако же, у тебя есть возможность указать в конструкторе таблицы как предполагаемый размер данных, так и LoadFactor. Жаль, что эти параметры можно указать только в конструкторе. Однако, если тебе надо поменять размер индекса на много, то можно смело создавать новую хеш-таблицу для индекса и "перелить" в нее индексы. Стоимость этой операции практически равна внутреннему rehash(), однако ты сделаешь это однократно. (если не создать сразу таблицу необходимого размера, то rehash может быть выполнен неоднократно).
Хотя, говоря начистоту, мне способ реализации дотнетной хеш-таблицы не нравится. Мне больше нравится способ, где в каждом вхождении основной хеш-таблицы хранится сортированный массив. Подобные хеш-таблицы лучше предназначены для активной вставки/удаления большого числа элементов. Если будет не лень, то напишу подобный хеш и выложу для всеобщего пользования. (Писал когда-то именно такой на С++, ибо std::map не удовлетворял на больших наборах)
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, BaZa, Вы писали: BZ>>Мне просто, например, интересно, так ли необходимо хранение методов в ООСУБД (как в Gemstone и O2)? S>Ну, вообще-то, лично я бы постеснялся назвать базу без хранения методов объектно-ориентированной. Поскольку из пяти концепций объектно-ориентированного программирования поддерживаются только две: идентифицируемость и наследование. О поведении, вместе с инкапсуляцией и полиморфизмом, можно забыть. Не вполне очевидно, нужно ли вообще наследование без полиморфизма.
Это вопрос проектирования.
В трехзвенке будет храниться код в исполняемых файлах на стороне сервера, и какая разница клиенту.
Или архитектура вроде Oracle Forms, когда приложения целиком хранятся на сервере СУБД.
То есть с уровнем "объектно-ориентированности" движка СУБД прямой связи нет.
Если подумать — найдется способ, как запихнуть код поближе к объекту, вопрос для чего, с какой целью.
...А отсюда наливаем, когда рецепт написан совсем неразборчиво...
Здравствуйте, Михаил, Вы писали: М>Это вопрос проектирования. М>В трехзвенке будет храниться код в исполняемых файлах на стороне сервера, и какая разница клиенту. М>Или архитектура вроде Oracle Forms, когда приложения целиком хранятся на сервере СУБД. М>То есть с уровнем "объектно-ориентированности" движка СУБД прямой связи нет. М>Если подумать — найдется способ, как запихнуть код поближе к объекту, вопрос для чего, с какой целью.
В частности, для того, чтобы работали нормальные запросы. В современных ОРМ системах это не так. Чтобы вызвать полиморфный метод, объект надо "поднять" в кэш. Чтобы выполнить поиск объектов по предикату, их нужно "спустить" в СУБД. Мы не обсуждаем клиента. Клиенту вообще торчит только SOAP сервис, и ему наплевать есть ли там внутри СУБД.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали: V>А я намекал как раз на хеш-способ организации этих самых индексов в ФИЗИЧЕСКОЙ памяти. Ибо как раз они дают быстрый доступ и вставку. Немного непонятно, как ты собрался быстро вставлять в B-индекс? Если я не ошибаюсь, то надо двигать в памяти все миллионы вхождений индексируемого значения?
Ошибаешься. Во-первых, B+ дерево имеет логарифмическое время выполнения всех операций — вставки, удаления, и поиска. Ничего двигать вообще не надо. Хэши, применяемые в СУБД, устроены совсем не так, как ты привык видеть в памяти. Потому что там rehash с переливанием, предлагаемый тобой — это выстрел себе в ногу. Рекомендую ознакомиться с литературой. Например, есть неплохая книга Гарсиа-Молина со товарищи.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Михаил, Вы писали: М>>Это вопрос проектирования. М>>В трехзвенке будет храниться код в исполняемых файлах на стороне сервера, и какая разница клиенту. М>>Или архитектура вроде Oracle Forms, когда приложения целиком хранятся на сервере СУБД. М>>То есть с уровнем "объектно-ориентированности" движка СУБД прямой связи нет. М>>Если подумать — найдется способ, как запихнуть код поближе к объекту, вопрос для чего, с какой целью. S>В частности, для того, чтобы работали нормальные запросы. В современных ОРМ системах это не так. Чтобы вызвать полиморфный метод, объект надо "поднять" в кэш. Чтобы выполнить поиск объектов по предикату, их нужно "спустить" в СУБД. Мы не обсуждаем клиента. Клиенту вообще торчит только SOAP сервис, и ему наплевать есть ли там внутри СУБД.
По-моему, запросы хорошо работают, когда есть быстрые индексы, оптимизация алгоритма выборки и т.п.
То есть скорость запроса — это структура данных, связи между объектами, алгоритмы поиска и сортировки, наконец параметры железа. Но только не наличие или отсутсвие хранимых функций у объектов.
С такой точки зрения вообще все равно, в каком формате выполняемый код хранится.
Преимущества одного формата над другим — поведение в условиях многозадачности, большого количества активных юзеров, параллельных транзакций, также объектов БД — их типов и экземпляров.
...А отсюда наливаем, когда рецепт написан совсем неразборчиво...
Это почти ObjectStore. С нормальным С++. И с транзакциями.
Правда, с SQL там туговато...
V>я бы не отказался в коде писать нечто (некий С++ — подобный язык, например): V>
Здравствуйте, Михаил, Вы писали: М>По-моему, запросы хорошо работают, когда есть быстрые индексы, оптимизация алгоритма выборки и т.п.
Да. М>То есть скорость запроса — это структура данных, связи между объектами, алгоритмы поиска и сортировки, наконец параметры железа. Но только не наличие или отсутсвие хранимых функций у объектов.
Мы говорим про возможность формулировать запросы. М>С такой точки зрения вообще все равно, в каком формате выполняемый код хранится.
Если его нельзя использовать в запросах — не все равно. М>Преимущества одного формата над другим — поведение в условиях многозадачности, большого количества активных юзеров, параллельных транзакций, также объектов БД — их типов и экземпляров.
Нет. Эти преимущества уже давно получены. Теперь надо получить преимущество в скорости разработки. ORM добавляет много рутинной работы.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
М>>С такой точки зрения вообще все равно, в каком формате выполняемый код хранится. S>Если его нельзя использовать в запросах — не все равно. М>>Преимущества одного формата над другим — поведение в условиях многозадачности, большого количества активных юзеров, параллельных транзакций, также объектов БД — их типов и экземпляров. S>Нет. Эти преимущества уже давно получены. Теперь надо получить преимущество в скорости разработки. ORM добавляет много рутинной работы.
Кажется, я не совсем понимаю, что надо такого, чего для щастья не хватает принципиально. Пример в студию?
...А отсюда наливаем, когда рецепт написан совсем неразборчиво...
Здравствуйте, Михаил, Вы писали: М>Кажется, я не совсем понимаю, что надо такого, чего для щастья не хватает принципиально.
Вижу. М>Пример в студию? Re[23]: Объектные базы как они есть
Здравствуйте, vdimas, Вы писали:
V>Не смотришь в корень или я недостаточно выразил свою мысль. Мне, например, непонятно назначение индекса по суррогатному (логическому) ключу, если мне не нужен сам суррогатный ключ. ForeignKey иже с ним.
Очень простая причина. Уменьшение кол-ва задействованных объектов в алгоритме. Что касается foreignkey — то это не только правило ссылочной целостности, но и суррогатный индекс на ссылаемый аттрибут для быстрого его выполнения.
V>А я намекал как раз на хеш-способ организации этих самых индексов в ФИЗИЧЕСКОЙ памяти. Ибо как раз они дают быстрый доступ и вставку. Немного непонятно, как ты собрался быстро вставлять в B-индекс? Если я не ошибаюсь, то надо двигать в памяти все миллионы вхождений индексируемого значения?
Нет при вставке двигаются только в одно сегменте. То есть сложность почти как при поиске. При нехватке места — значения балансируются с соседними сегментами. Но он ни для одной операции не задействует все сегменты со значениями(кроме создания самого дерева, конечно).
GZ>>PS: только не надо намекать на хеши Net. Оссобенно в связи с их тактикой пересчета хеша. Для больших данных — это нереальный алгоритм.
V>Ну да, они там размер основной таблицы хеша пересчитывают при росте количества данных. Однако же, у тебя есть возможность указать в конструкторе таблицы как предполагаемый размер данных, так и LoadFactor. Жаль, что эти параметры можно указать только в конструкторе. Однако, если тебе надо поменять размер индекса на много, то можно смело создавать новую хеш-таблицу для индекса и "перелить" в нее индексы. Стоимость этой операции практически равна внутреннему rehash(), однако ты сделаешь это однократно. (если не создать сразу таблицу необходимого размера, то rehash может быть выполнен неоднократно).
У меня есть индексы размером в несколько мегабайт(даже больше сотни). Так что эта операция не очень быстрая.
V>Хотя, говоря начистоту, мне способ реализации дотнетной хеш-таблицы не нравится. Мне больше нравится способ, где в каждом вхождении основной хеш-таблицы хранится сортированный массив. Подобные хеш-таблицы лучше предназначены для активной вставки/удаления большого числа элементов. Если будет не лень, то напишу подобный хеш и выложу для всеобщего пользования. (Писал когда-то именно такой на С++, ибо std::map не удовлетворял на больших наборах)
Каким образом ты собрался сортировать строки. Для хеша важно нормальное распределение значений. Для нормального распределения нужен функция хеширования. Но я не знаю функций хеширования которая могла бы оставлять информацию о порядке для сортировки.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vdimas, Вы писали: V>>А я намекал как раз на хеш-способ организации этих самых индексов в ФИЗИЧЕСКОЙ памяти. Ибо как раз они дают быстрый доступ и вставку. Немного непонятно, как ты собрался быстро вставлять в B-индекс? Если я не ошибаюсь, то надо двигать в памяти все миллионы вхождений индексируемого значения? S>Ошибаешься. Во-первых, B+ дерево имеет логарифмическое время выполнения всех операций — вставки, удаления, и поиска. Ничего двигать вообще не надо. Хэши, применяемые в СУБД, устроены совсем не так, как ты привык видеть в памяти. Потому что там rehash с переливанием, предлагаемый тобой — это выстрел себе в ногу. Рекомендую ознакомиться с литературой. Например, есть неплохая книга Гарсиа-Молина со товарищи.
Я вообще-то говорил о реализации Hashtable в дотнете, так что твои рекомендации относятся к команде Microsoft.
И если ты следил за нитью разговора, то речь идет о хранении данных в ОП.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, vdimas, Вы писали:
V>>Не смотришь в корень или я недостаточно выразил свою мысль. Мне, например, непонятно назначение индекса по суррогатному (логическому) ключу, если мне не нужен сам суррогатный ключ. ForeignKey иже с ним. GZ>Очень простая причина. Уменьшение кол-ва задействованных объектов в алгоритме. Что касается foreignkey — то это не только правило ссылочной целостности, но и суррогатный индекс на ссылаемый аттрибут для быстрого его выполнения.
Блин, похоже все потеряли нить разговора. Речь-то идет о хранении данных в ОП. (о подобной гипотетической возможности). Дык, если все хранится в памяти произвольного доступа, то как суррогатный ключ мне поможет уменьшить кооличество задействованных объектов??? Вместо foreighkey вообще просто коллекция объектов на стороне master и ссылка на мастер на стороне detail (для one-to-many). Куда уж быстрее, если у меня и так все данные правильно сгруппированы и мне искать и выбирать ничего не надо, все уже выбрано и найдено.
V>>А я намекал как раз на хеш-способ организации этих самых индексов в ФИЗИЧЕСКОЙ памяти. Ибо как раз они дают быстрый доступ и вставку. Немного непонятно, как ты собрался быстро вставлять в B-индекс? Если я не ошибаюсь, то надо двигать в памяти все миллионы вхождений индексируемого значения? GZ>Нет при вставке двигаются только в одно сегменте. То есть сложность почти как при поиске. При нехватке места — значения балансируются с соседними сегментами. Но он ни для одной операции не задействует все сегменты со значениями(кроме создания самого дерева, конечно).
V>>Хотя, говоря начистоту, мне способ реализации дотнетной хеш-таблицы не нравится. Мне больше нравится способ, где в каждом вхождении основной хеш-таблицы хранится сортированный массив. Подобные хеш-таблицы лучше предназначены для активной вставки/удаления большого числа элементов. Если будет не лень, то напишу подобный хеш и выложу для всеобщего пользования. (Писал когда-то именно такой на С++, ибо std::map не удовлетворял на больших наборах)
GZ>Каким образом ты собрался сортировать строки. Для хеша важно нормальное распределение значений. Для нормального распределения нужен функция хеширования. Но я не знаю функций хеширования которая могла бы оставлять информацию о порядке для сортировки.
Попробую пояснить. Хеш-функция и ф-ия сортировки — это разные ф-ии. Первая применяется для "разреживания" данных. Т.е. вместо одного бинарного индекса со временем доступа, кратным логирифму, у нас получается исходное время доступа, деленное на количество элементов в хеш-таблице (при удачно подобранной хеш-функции и соотв. данных).
Т.е. в моем способе, хеш-таблица — это массив массивов индексов. Обычно размер хеш-таблицы я беру такой, чтобы каждое ее вхождение содержало сортированный индекс от 2-х до 8-ми (грубо) ключей. В этом случае целессобразно сами индексы хранить как обычные сортированные последовательности и выполнять в них двоичный поиск.
Т.е. алгоритм такой:
берем хеш-фию и по ней находим ячейку хеш-таблицы. В этой ячейке хранится сортированная последовательность ключей, в которой мы выполняем бинарный поиск. На больших наборах данных такая организация хеш-таблицы ведет себя весьма достойно.
GZ>С уважением, Gleb.
Здравствуйте, Alexey Rovdo, Вы писали: AR>По вашему, если методы будут в самой СУБД, то ей не прийдется поднимать в кэш такой объект при обработке запроса?
Не обязательно. Я уже писал почему.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали:
V>Блин, похоже все потеряли нить разговора. Речь-то идет о хранении данных в ОП. (о подобной гипотетической возможности). Дык, если все хранится в памяти произвольного доступа, то как суррогатный ключ мне поможет уменьшить кооличество задействованных объектов??? Вместо foreighkey вообще просто коллекция объектов на стороне master и ссылка на мастер на стороне detail (для one-to-many). Куда уж быстрее, если у меня и так все данные правильно сгруппированы и мне искать и выбирать ничего не надо, все уже выбрано и найдено.
Тут ты задвинул две проблемы. Допустим у нас есть нев.. ну в общем очень большой справочник операций сделанных над документами. Операций делаются по несколько тысяч за день. Можем ли мы сохранить ссылки на операции из документов? Нет не можем. Иначе у нас получится что связи (массив OID или указателей, как тебе будет угодно) намного больше чем сам документ. То есть, проблема избыточности связей существует (что в реляционке решается нормализацией). При этом есть такая шняга, что если документ убили, операции о нем не должны исчезнуть.
Вторая проблема которую ты решил не видеть. Нам нужно найти операции просмотра с определенным документом. Ну и что тут делать? Просматривать все операции? Не лучше ли поднять индекс и сделать это весело и быстро, чем тормозить и грустно
И таких примеров избыточности связей, когда память под связи на порядок больше чем сам объект, могу привести вагон.
Специально выделил в отдельное сообщение поскольку немного отошли от основной темы (на усмотрение модераторов).
GZ>>Каким образом ты собрался сортировать строки. Для хеша важно нормальное распределение значений. Для нормального распределения нужен функция хеширования. Но я не знаю функций хеширования которая могла бы оставлять информацию о порядке для сортировки.
V>Попробую пояснить. Хеш-функция и ф-ия сортировки — это разные ф-ии. Первая применяется для "разреживания" данных. Т.е. вместо одного бинарного индекса со временем доступа, кратным логирифму, у нас получается исходное время доступа, деленное на количество элементов в хеш-таблице (при удачно подобранной хеш-функции и соотв. данных).
V>Т.е. в моем способе, хеш-таблица — это массив массивов индексов. Обычно размер хеш-таблицы я беру такой, чтобы каждое ее вхождение содержало сортированный индекс от 2-х до 8-ми (грубо) ключей. В этом случае целессобразно сами индексы хранить как обычные сортированные последовательности и выполнять в них двоичный поиск.
Для 2-8 ключей сортированный индекс не нужен.
V>Т.е. алгоритм такой: V>берем хеш-фию и по ней находим ячейку хеш-таблицы. В этой ячейке хранится сортированная последовательность ключей, в которой мы выполняем бинарный поиск. На больших наборах данных такая организация хеш-таблицы ведет себя весьма достойно.
Ну особо-то от Microsoft не отличается.
За что я люблю B+ деревья, то что они универсальны для всех случаев. Максимум при поиске — Nlog(N) операций. Плюс хранение в сортированном виде.
Какие недостатки у кэша.
1. Сложность нахождения хеш-функции при которой есть нормальное распределение. Если у нас хорошая функция, то поиск происходит за O(1). Если плохая, то O(N).
2. При повторяемости данных — хеш теряет свои свойства.
3. При вставке большого кол-ва элементов — нужно расширять хеш таблицу. Иначе получаем O(N).
Microsoft решили вопрос кардинально. Повторяемость запрещена(что очень плохо). Поиск всегда O(1). Но за счет чего. За счет того, либо нужно сразу прогнозировать количество элементов и выделять память, либо при некоторых вставках сразу же получим неплохое торомжение. И есть возможность даже при выделенной памяти получить повторное хеширование всех элементов(что будет совсем хреново).
В твоем случае, почти все недостатки (как и у всех хешей) присутствует. И сразу еще одна — если мы допускаем что у нас до 8 одинаковых значений, то у нас нет особых гарантий и от 1000. То есть, приближаемся к O(N).
Здравствуйте, GlebZ, Вы писали:
V>>Т.е. алгоритм такой: V>>берем хеш-фию и по ней находим ячейку хеш-таблицы. В этой ячейке хранится сортированная последовательность ключей, в которой мы выполняем бинарный поиск. На больших наборах данных такая организация хеш-таблицы ведет себя весьма достойно. GZ>Ну особо-то от Microsoft не отличается.
Да ну ни хрена себе не отличается, принципиально по-другому...
GZ>За что я люблю B+ деревья, то что они универсальны для всех случаев. Максимум при поиске — Nlog(N) операций. Плюс хранение в сортированном виде. GZ>Какие недостатки у кэша. GZ>1. Сложность нахождения хеш-функции при которой есть нормальное распределение. Если у нас хорошая функция, то поиск происходит за O(1). Если плохая, то O(N). GZ>2. При повторяемости данных — хеш теряет свои свойства. GZ>3. При вставке большого кол-ва элементов — нужно расширять хеш таблицу. Иначе получаем O(N). GZ>Microsoft решили вопрос кардинально. Повторяемость запрещена(что очень плохо). Поиск всегда O(1). Но за счет чего. За счет того, либо нужно сразу прогнозировать количество элементов и выделять память, либо при некоторых вставках сразу же получим неплохое торомжение. И есть возможность даже при выделенной памяти получить повторное хеширование всех элементов(что будет совсем хреново). GZ>В твоем случае, почти все недостатки (как и у всех хешей) присутствует. И сразу еще одна — если мы допускаем что у нас до 8 одинаковых значений, то у нас нет особых гарантий и от 1000. То есть, приближаемся к O(N).
Я же русским языком сказал, что в ячейках хеш-таблицы хранятся сортированные индексы, в которых всегда поиск NLog(N).
Я все-таки буду писать подобную хеш-таблицу для второго дотнета (нужна самим подобная), учитывая твое замечание, предусмотрю в конструкторе фабрику для создания сортированных индексов в ячейках таблицы. Т.е., если будут подозрения плохое хеширование, можно подать фабрику для B+ индексов в ячейках. По умолчанию будет простой сортированный массив, в котором опять же трудоемкость не более NLog(N).
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, vdimas, Вы писали:
V>>Блин, похоже все потеряли нить разговора. Речь-то идет о хранении данных в ОП. (о подобной гипотетической возможности). Дык, если все хранится в памяти произвольного доступа, то как суррогатный ключ мне поможет уменьшить кооличество задействованных объектов??? Вместо foreighkey вообще просто коллекция объектов на стороне master и ссылка на мастер на стороне detail (для one-to-many). Куда уж быстрее, если у меня и так все данные правильно сгруппированы и мне искать и выбирать ничего не надо, все уже выбрано и найдено. GZ>Тут ты задвинул две проблемы. Допустим у нас есть нев.. ну в общем очень большой справочник операций сделанных над документами. Операций делаются по несколько тысяч за день. Можем ли мы сохранить ссылки на операции из документов? Нет не можем. Иначе у нас получится что связи (массив OID или указателей, как тебе будет угодно) намного больше чем сам документ. То есть, проблема избыточности связей существует (что в реляционке решается нормализацией).
Бред, насчет нормализации. Здесь речь не об этом, а о том, где хранить индексы. Ты же не считаешь индекс в базе — избыточной информацией? Вот и здесь, подобный массив — суть индекс.
GZ>Вторая проблема которую ты решил не видеть. Нам нужно найти операции просмотра с определенным документом. Ну и что тут делать? Просматривать все операции? Не лучше ли поднять индекс и сделать это весело и быстро, чем тормозить и грустно GZ>И таких примеров избыточности связей, когда память под связи на порядок больше чем сам объект, могу привести вагон.
А никто не запрещает хранить связи вне объекта. Если мы рассматриваем ООСУБД полностью в памяти, то храни эти индексы там, где будешь использовать. Например в неком глобалдьном объекте DocumentsHistory.
GZ>При этом есть такая шняга, что если документ убили, операции о нем не должны исчезнуть.
Значит, документ физически не убит, а переведен в состояние "убит". Возможно, что при переходе в это состояние документ прочищает ненужные более подчиненные данные, оставляя лишь основные, либо же вообще, документ заменяется некоим стабом, несущим общую информацию о документе. В реальной базе я часто видел подобные стабы, и тут как раз имеем вовсю разгул избыточности. Т.е. в журнале документов фигурируют не сами документы, а "сокращенные" записи о них, типа {"Дата", "Сумма", "Корреспондент", "Кем создан"}. Если у нас подобный журнал документов хранит массив интерфейсов типа IDocumentInfo (который может имплементить как сам документ, так и потом "посмертный" стаб), то мы гораздо лучше избавляемся от избыточности данных. (в общем, в ООП совершенно другие подходы).
Тут есть еще один момент. Мы можем избавится от избыточности данных и в случае foreign key. Нам необязательно в подчиненном объекте иметь ссылку на ключ мастера. Т.е. для строк документа, кои не имеют смысла вне самого документа, мы можем ссылку на документ не хранить, ибо строки документа будут обрабатываться самим документом, который эти строки хранит. Т.е., в терминах реляционки, foreig key отсутствует, однако у нас есть индекс по нему и автоматически полученное ограничение целостности.
Здравствуйте, vdimas, Вы писали:
V>Бред, насчет нормализации.
Бредовые базы и в РСУБД встречаются. Например когда размер индексов 200% от размера БД. Такая шняга уже тормозит за счет индексов безбожно. Поэтому даже в плане нормализации и индексированности нужно соблюдать меру(хотя там и других проблем достаточно). V>Здесь речь не об этом, а о том, где хранить индексы. Ты же не считаешь индекс в базе — избыточной информацией? Вот и здесь, подобный массив — суть индекс.
Разговор шел нужен ли индекс или нет. Возьми другую информацию, например дату, или тип операции. В любом случае, лучше чем декларативный язык запросов с жуткими механизмами оптимизации задачу поиска никто не решит.
V>А никто не запрещает хранить связи вне объекта. Если мы рассматриваем ООСУБД полностью в памяти, то храни эти индексы там, где будешь использовать. Например в неком глобалдьном объекте DocumentsHistory.
я в такой модели много полезного есть.
V>Значит, документ физически не убит, а переведен в состояние "убит". Возможно, что при переходе в это состояние документ прочищает ненужные более подчиненные данные, оставляя лишь основные, либо же вообще, документ заменяется некоим стабом, несущим общую информацию о документе. В реальной базе я часто видел подобные стабы, и тут как раз имеем вовсю разгул избыточности. Т.е. в журнале документов фигурируют не сами документы, а "сокращенные" записи о них, типа {"Дата", "Сумма", "Корреспондент", "Кем создан"}. Если у нас подобный журнал документов хранит массив интерфейсов типа IDocumentInfo (который может имплементить как сам документ, так и потом "посмертный" стаб), то мы гораздо лучше избавляемся от избыточности данных. (в общем, в ООП совершенно другие подходы).
Это уже частности. В 99 процентах случаев — ограничиваются логическим удалением. Лучше когда переносится в особый журнал (содержащий только нужную информацию). А иногда по требованиям — все кроме аудита must die. Без следов. Клиент всегда прав.
V>Тут есть еще один момент. Мы можем избавится от избыточности данных и в случае foreign key. Нам необязательно в подчиненном объекте иметь ссылку на ключ мастера.
Наоборот. Мастер хранит коллекцию ссылок на подчиненные объекты. V>Т.е. для строк документа, кои не имеют смысла вне самого документа, мы можем ссылку на документ не хранить, ибо строки документа будут обрабатываться самим документом, который эти строки хранит. Т.е., в терминах реляционки, foreig key отсутствует, однако у нас есть индекс по нему и автоматически полученное ограничение целостности.
Нормальная ситуация для OODB. Со своими плюсами и недостатками. Особенно если этих строк 10000.
Здравствуйте, Cyberax, Вы писали:
C>Sinclair пишет:
>> C>Из-за дьявольски сложного семейства почтовых стандартов. >> Я же сказал "банального"
C>Слова "банальный", "корректный" и "email" — несовместимы. Даже банальный C>релей должен понимать все форматы адресов, если хочет быть корректным.
Ага, там самая веселуха начинается, когда надо залезть внутрь письма, например подпись вставить
GZ>Это уже частности. В 99 процентах случаев — ограничиваются логическим удалением. Лучше когда переносится в особый журнал (содержащий только нужную информацию).
Если переносится в отдельный журнал, то невозможно задать ограничения целостности. А в моем варианте, при имплементации IDocumentInfo — запросто.
GZ>А иногда по требованиям — все кроме аудита must die. Без следов. Клиент всегда прав.
Аудита чего? Все-равно хоть какая-то инфа должна остаться, иначе сама history не нужна.
V>>Тут есть еще один момент. Мы можем избавится от избыточности данных и в случае foreign key. Нам необязательно в подчиненном объекте иметь ссылку на ключ мастера. GZ>Наоборот. Мастер хранит коллекцию ссылок на подчиненные объекты. V>>Т.е. для строк документа, кои не имеют смысла вне самого документа, мы можем ссылку на документ не хранить, ибо строки документа будут обрабатываться самим документом, который эти строки хранит. Т.е., в терминах реляционки, foreig key отсутствует, однако у нас есть индекс по нему и автоматически полученное ограничение целостности. GZ>Нормальная ситуация для OODB. Со своими плюсами и недостатками. Особенно если этих строк 10000.
нормальная вполне ситуация, когда подчиненных строк не более 10000 в документе.
GZ>С уважением, Gleb.
Теперь понятно.
имхо это не есть хорошая идея — вот так смешивать SQL и объектную базу.
Если это так надо: IPerson и т.п. должны жить где-то внутри движка СУБД. Так же как план запроса живет внутри оракла.
Кстати, на SQL мир клином не сошелся. Хотя к сожалению, этот шаблон сильно влияет на образ мышления.
Во многих задачах можно жить и без него.
Например, см. http://www.cronos.ru
...А отсюда наливаем, когда рецепт написан совсем неразборчиво...
Здравствуйте, Михаил, Вы писали: М>Теперь понятно. М>имхо это не есть хорошая идея — вот так смешивать SQL и объектную базу.
А с чем надо смешивать объектную базу? М>Если это так надо: IPerson и т.п. должны жить где-то внутри движка СУБД. Так же как план запроса живет внутри оракла.
Совершенно верно. М>Кстати, на SQL мир клином не сошелся. Хотя к сожалению, этот шаблон сильно влияет на образ мышления.
Гм. Не вижу ничего плохого в SQL. Наоборот — практика показывает, что на нем гораздо труднее заставить сервер заниматься непроизводительной работой. А императивно это сделать очень легко.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, eao197, Вы писали:
E>Имхо, такие проблемы лечатся, если поднятие объекта из БД не означает автоматического поднятия всех объектов по его ссылкам. Тогда, для приведенного примера, в объекте-документе может быть ссылка на объект-историю. А уже в истории будет храниться список модификаций (тем или иным образом организованный). Если объект-документ извлекается из БД без объекта-истории, то нет проблем с производительностью.
E>Такой подход был в свое время реализован в POET -- там при загрузке объекта можно было указывать, что делать с объектами по ссылкам: либо грузить все, либо грузить определенные типы ссылок. А в Goods, если мне не изменяет память, ссылки между объектами реализовывались на основе "умных указателей". И реальный доступ к объекту через умный указатель осуществлялся только тогда, когда было обращение по этому указателю.
Речь идет не о поднятии связанных объектов при загрузке объекта, а о поднятии самих ссылок на эти связанные объекты. Проблема "избыточности связей", как правильно заметил GlebZ, ИМХО, существует.
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, eao197, Вы писали:
E>>Имхо, такие проблемы лечатся, если поднятие объекта из БД не означает автоматического поднятия всех объектов по его ссылкам. Тогда, для приведенного примера, в объекте-документе может быть ссылка на объект-историю. А уже в истории будет храниться список модификаций (тем или иным образом организованный). Если объект-документ извлекается из БД без объекта-истории, то нет проблем с производительностью.
E>>Такой подход был в свое время реализован в POET -- там при загрузке объекта можно было указывать, что делать с объектами по ссылкам: либо грузить все, либо грузить определенные типы ссылок. А в Goods, если мне не изменяет память, ссылки между объектами реализовывались на основе "умных указателей". И реальный доступ к объекту через умный указатель осуществлялся только тогда, когда было обращение по этому указателю.
S>Речь идет не о поднятии связанных объектов при загрузке объекта, а о поднятии самих ссылок на эти связанные объекты. Проблема "избыточности связей", как правильно заметил GlebZ, ИМХО, существует.
Если ссылки вынести в отдельный объект, то задача сводится с тому, о чем я написал
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Если ссылки вынести в отдельный объект, то задача сводится с тому, о чем я написал
Здесь проблема не только в чтении ссылок. Если речь идет о двунаправленной связи, то есть еще и проблема синхронного изменения. То есть, возмем пример рассматриваемый выше: документ и операции с ним. Документ хранит коллекцию ссылок на свои операции, а операция — ссылку на документ.
Так вот, например, я загрузил операцию (или мне ее вернула какая-нибудь функция) и решил изменить у нее ссылку на документ. То есть переприсвоить операцию другому документу (пример, конечно неудачный, но...). Я же должен соответствующие изменения сделать и в коллекциях ссылок старого и нового документа. Т.е. все равно эти коллекции сначала придется подгрузить. Так что выделяй в отдельный объект или нет — без разницы.
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, eao197, Вы писали:
E>>Если ссылки вынести в отдельный объект, то задача сводится с тому, о чем я написал
S>Здесь проблема не только в чтении ссылок. Если речь идет о двунаправленной связи, то есть еще и проблема синхронного изменения. То есть, возмем пример рассматриваемый выше: документ и операции с ним. Документ хранит коллекцию ссылок на свои операции, а операция — ссылку на документ. S>Так вот, например, я загрузил операцию (или мне ее вернула какая-нибудь функция) и решил изменить у нее ссылку на документ. То есть переприсвоить операцию другому документу (пример, конечно неудачный, но...). Я же должен соответствующие изменения сделать и в коллекциях ссылок старого и нового документа. Т.е. все равно эти коллекции сначала придется подгрузить. Так что выделяй в отдельный объект или нет — без разницы.
Что-то я не очень понимаю в чем суть проблемы. Если по условиям задачи возможно, что в объекте "операция над документом" можно поменять ссылку на изменяемый документ (что само по себе странно), то можно организовать коллекцию ссылок таким образом, чтобы операции вставки/удаления были дешевыми. Например, вместо вектора ссылок использовать двусвязный список (каждый элемент содержит собственно ссылку + ссылки на предыдущий/следующий элементы списка) или map на основе B+ дерева.
Имхо, ситуация здесь точно такая же, как при работе со структурами в ОП. Мы можем пренебречь скоростью некоторых операций (т.к. как удаления операций из истории) и выбрать более эффективный в смысле расхода памяти контейнер для хранения ссылок (вектор). А можем наоборот, постараться обеспечить высокую скорость за счет высокой ресурсоемкости (списки, деревья).
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Если речь идет о большой системе, если она модульная, и если пишется совместно многими программистами, то двунаправленные связи в домейн-модели, если они вшиты в доменные классы будут представлять из себя большой геморрой, так как будут вносить много зависимостей между модулями на логическом уровне доменной модели. И что самое противное — циклических зависимостей.
И вторая проблема, как ты правильно написал, если есть две подсистемы и их объекты никак не связаны, а связываются они только в третьей подсистеме, то велика вероятность, что эта связь в достаточно большом количестве подзадач задействована не будет и ее было бы неправильно засовывать в объекты, чисто с точки зрения производительности/памяти.
Вот и возникает мысль о том что объявлять связи нужно отдельно от классов доменных объектов. И даже может не только объявлять, но и кэшировать как-то в отдельных структурах, а не при помощи перекрестных ссылок (коллекций ссылок).
Только вот я тут думаю уже на протяжении полугода как бы это сделать. Уж больно все сложно получается. Так — что у меня крыша съезжает .
Здравствуйте, eao197, Вы писали:
E>Что-то я не очень понимаю в чем суть проблемы. Если по условиям задачи возможно, что в объекте "операция над документом" можно поменять ссылку на изменяемый документ (что само по себе странно), то можно организовать коллекцию ссылок таким образом, чтобы операции вставки/удаления были дешевыми. Например, вместо вектора ссылок использовать двусвязный список (каждый элемент содержит собственно ссылку + ссылки на предыдущий/следующий элементы списка) или map на основе B+ дерева.
А я не про организацию в памяти говорю, а про то, что чтобы изменить эту коллекцию в памяти (пусть и бытрым алгоритмом) ее нужно сначала подчитать из базы. Т.е. вроде как бы изначально то я хотел переприсвоить только одну ссылку, но поскольку связь двунаправленная — неявно подгрузиться коллекция с обратной стороны. Ето вот проблема.
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, eao197, Вы писали:
E>>Что-то я не очень понимаю в чем суть проблемы. Если по условиям задачи возможно, что в объекте "операция над документом" можно поменять ссылку на изменяемый документ (что само по себе странно), то можно организовать коллекцию ссылок таким образом, чтобы операции вставки/удаления были дешевыми. Например, вместо вектора ссылок использовать двусвязный список (каждый элемент содержит собственно ссылку + ссылки на предыдущий/следующий элементы списка) или map на основе B+ дерева.
S>А я не про организацию в памяти говорю, а про то, что чтобы изменить эту коллекцию в памяти (пусть и бытрым алгоритмом) ее нужно сначала подчитать из базы. Т.е. вроде как бы изначально то я хотел переприсвоить только одну ссылку, но поскольку связь двунаправленная — неявно подгрузиться коллекция с обратной стороны. Ето вот проблема.
Нет, это проблема, только если выбранная коллекция требует для своего изменения полной загрузки себя в память. Например, если коллекция -- это вектор (непрерывная последовательность ссылок). А если коллекция -- это дерево, то в память нужно будет загрузить только вершину и те промежуточные узлы, которые ведут к модифицируемому узлу. И если речь идет о B+ дереве, например, то изятие одного элемента из дерева в несколько миллионов элементов потребует доступа всего к нескольким узлам (страницам) дерева.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, stalcer, Вы писали:
S>А ведь и та и другая ситуация может быть с равной вероятностью. И придумать алгоритм, который бы не грузил лишнее в обоих случаях — вот хитрая задачка.
Имхо, это из области нахождения компромиса между скоростью/ресурсоемкостью.
По отношению к ООСУБД более интересно другое: должны ли эти алгоритмы быть частью ООСУБД или ООСУБД должна предоставлять средства для их эффективной реализации на прикладном уровне?
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Имхо, это из области нахождения компромиса между скоростью/ресурсоемкостью.
Да, но нужно подмать как бы исхитриться и т.п. Может чего и получится .
E>По отношению к ООСУБД более интересно другое: должны ли эти алгоритмы быть частью ООСУБД или ООСУБД должна предоставлять средства для их эффективной реализации на прикладном уровне?
Если само понятие двунаправленных связей — определено в ООСУБД, то да, должны быть частью ООСУБД. По моему, двунаправленные связи совсем не лишние в ООСУБД. Наоборот, очень естественно иметь объекты и связи между ними. И к UML ближе. Ссылочные аттрибуты, в каком-то смысле, более надуманное понятие.
М>>имхо это не есть хорошая идея — вот так смешивать SQL и объектную базу. S> А с чем надо смешивать объектную базу?
не базу смешивать, а скорее языки, и не смешивать, а изменять (мне так кажется):
РСУБД-О/РСУБД — SQL
ООСУБД — OQL
М>>Кстати, на SQL мир клином не сошелся. Хотя к сожалению, этот шаблон сильно влияет на образ мышления. S>Гм. Не вижу ничего плохого в SQL. Наоборот — практика показывает, что на нем гораздо труднее заставить сервер заниматься непроизводительной работой. А императивно это сделать очень легко.
Ничего плохого в SQL и нет, просто это язык работы с реляционными данными, а для объектных есть OQL
Здравствуйте, BaZa, Вы писали:
е базу смешивать, а скорее языки, и не смешивать, а изменять (мне так кажется): BZ>РСУБД-О/РСУБД — SQL BZ>ООСУБД — OQL
Угу. А еще я туда ем. BZ>Ничего плохого в SQL и нет, просто это язык работы с реляционными данными, а для объектных есть OQL
Стандарт OQL — основная причина фиаско ODBMS.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S> Стандарт OQL — основная причина фиаско ODBMS.
Ну это вы уже загнули. Наверное, если бы вы сказали "... основная причина фиаско ODMG", я бы еще согласился. Но с точки зрения ООСУБД наличие или отсутствие поддержки OQL само по себе ничего не меняет. Просто OQL — далеко не самый удобный способ выборки объектов "по значению" из тех, что доступны в современных ООСУБД. Лично я уже описывал свои сомнения в целесообразности использования декларативных языков запросов в работе с ООСУБД, но раз уж он (OQL) есть, то никак не вредит одним лишь своим присутствием.
BZ>>Ничего плохого в SQL и нет, просто это язык работы с реляционными данными, а для объектных есть OQL S> Стандарт OQL — основная причина фиаско ODBMS.
ну, это сильно сказано. Хотя, возможно, в этом есть доля правды — именно из подобных соображений производители ООСУБД реализуют его не по ODMG 3, а исходя из соображений usability и пр.
На самом деле OQL лучше всего описан во втором ODMG (по крайней мере по сравнению с третим)
Здравствуйте, BaZa, Вы писали:
BZ>На самом деле OQL лучше всего описан во втором ODMG (по крайней мере по сравнению с третим)
А у тебя есть третья спецификация?
Здравствуйте, BaZa, Вы писали:
BZ>ООСУБД не должна содержать такие алгоритмы, так как учет всех таких ситуаций (и способов их решения) приведет к разрастанию такой СУБД до махины, в которой ни Вы, ни я, ни кто-либо вообще не разберется. Так что мне кажется достаточно (более чем) просто предоставить инструменты создания таких алгоритмов. Например, Versant VDS поддерживает B+ (т.е когда для коллекции можно указать, что ее надо хранить в B+) — вот пример наличия инструментов (предоставляемых) для реализации алгоритмов оптимизации хранения.
Нет уж, простите. Речь же шла о кэшировании связей. Этим СУБД очень как должна заниматься. Или вы предлагаете вообще отказаться от двунаправленных связей — как понятия? И переложить их организацию на плечи прикладного программиста? А СУБД будет только поддерживать ссылки и коллекции (ссылок)?
Так что если понятие двунаправленных связей вкладывать в ООСУБД, то все эти алгоритмы должны присутствовать. ИМХО ничего не будет разрастаться, просто вдобавок к одному базовому понятию — объект (класс), будет еще и другое — связь (ассоциация). И я специально подчеркнул, что даже UML на это пошел. Так что не вижу здесь ничего страшного. А полезного — вижу много.
Но, ведь релляционные базы как-то с этим справляются. Ведь там тоже таблица может быть маленькой или большой. И планы выполнения запроса получаются разные: FULL-SCAN или INDEX-SEARCH. Но, какой-то внутренний формат, используемый СУБД все равно есть. И работает он с обеими ситуациями.
Я вообщем-то и не предлагаю выставлять наружу различные типы коллекций (SmallSet, BTreeSet, HugeSet, SmallList, HugeList, ...). Я именно и предлагаю подумать, как это все можно унифицировать. Именно с точки зрения эффективности СУБД.
Одно из требований (желаний) я определил: Надо сделать так, чтобы при изменении одного конца связи не нужно было грузить всю коллекцию (или объект со ссылкой) на другом конце.
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, eao197, Вы писали:
S>Но, ведь релляционные базы как-то с этим справляются. Ведь там тоже таблица может быть маленькой или большой. И планы выполнения запроса получаются разные: FULL-SCAN или INDEX-SEARCH. Но, какой-то внутренний формат, используемый СУБД все равно есть. И работает он с обеими ситуациями.
Реляционные базы -- это совсем другая песня. Там ведь вообще нет возможности напрямую объект в БД запихнуть. Нужно либо делать это ручками (тогда у нас нет как такового атрибута множество ссылок на изменения документа, а есть несколько SQL запросов на сериализацию/десериализацию этого атрибута). И тогда мы получаем возможность гибко управлять ссылками, т.к. мы можем делать небольшие запросы, изменяющие только часть ссылок.
Либо нужно воспользоваться инструментами O/R Mapping-а. И тогда получаются теже самые SQL запросы, но вот насколько мы их контролируем и насколько эффективно они будут обрабатывать подобные изменения ссылок -- второй вопрос. Поскольку я не специалист в O/R Mapping-е, то ничего по этому поводу не скажу.
S>Я вообщем-то и не предлагаю выставлять наружу различные типы коллекций (SmallSet, BTreeSet, HugeSet, SmallList, HugeList, ...). Я именно и предлагаю подумать, как это все можно унифицировать. Именно с точки зрения эффективности СУБД.
S>Одно из требований (желаний) я определил: Надо сделать так, чтобы при изменении одного конца связи не нужно было грузить всю коллекцию (или объект со ссылкой) на другом конце.
Но тогда нужно определить еще и условия, при которых этого не нужно делать. Ведь если все коллекции ссылок будут обрабатываться таким образом независимо от их размера, то накладные расходы на хранение этих коллекций могут оказаться слишком высокими.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, eao197, Вы писали:
S>>>Одно из требований (желаний) я определил: Надо сделать так, чтобы при изменении одного конца связи не нужно было грузить всю коллекцию (или объект со ссылкой) на другом конце.
E>>Но тогда нужно определить еще и условия, при которых этого не нужно делать. Ведь если все коллекции ссылок будут обрабатываться таким образом независимо от их размера, то накладные расходы на хранение этих коллекций могут оказаться слишком высокими.
S>В базах данных, в этом смысле, есть один очень положительный момент: основное время тратиться на работу с диском. Это само по себе, конечно очень плохо, но зато можно не экономить на работе в кэше. То есть формат данных в кэше можно сделать и более навороченным, по сравнению, например, со стандартными коллекциями C++.
Чесно говоря я не понял, причем тут кэш и экономия времении, а так же навороченность коллекций
S>В данном конкретном случае — всегда нужно стремиться к тому, чтобы не загружать зря коллекцию с другой стороны. Так как накладные расходы на загрузку будут несоизмеримо больше, чем работа с кэшем.
Это да, согласен.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
S>Я о чем и говорю: коллекции в таком случае должны быть построены так, чтобы не нужно было подгружать ее вообще. Может быть даже просто запоминать все изменения в какой-то другой структуре, для того чтобы когда коллекция реально потребуется — загрузить ее (коллекцию) и скорректировать.
S>Тут еще фишка в том, что в большинстве случаев коллекции — маленькие и без разницы грузить ее всю или только часть. Это все равно одно обращение к базе. А вот если совсем не грузить , это да, это хорошо.
S>А еще может быть и обратная ситуация. Когда коллекция уже загружена, и из нее, например, удаляем объект. Или еще круче: делаем просто Clear(). И прикинь, что для этого необходимо будет подгрузить все соответствующие children объекты, чтобы изменить в них ссылки.
S>А ведь и та и другая ситуация может быть с равной вероятностью. И придумать алгоритм, который бы не грузил лишнее в обоих случаях — вот хитрая задачка.
Все, что применимо в обычном программировании, применимо и для БД. Реально можно обходится и без индексов для подчиненных коллекций если ее применять ввиде двухнаправленного связного списка, а начало и конец держать в родителе (при этом запись может содержать относительное место в БД например номер записи). При этом всиавка,Clear() вообще простая операция.
Еще лично мое видение и повторюсь в сотый раз, это делать объектную надстройку над записями (записью) в БД. Нужно только считать данные с нужно страницы, и не держать огромное количество объектов в памяти, а только те которые необходимы при данной транзакции.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
BaZa wrote:
> C>Я работал немного с Versant в свое время — Hibernate его (по моим > C>ощущениям) намного превосходит в удобстве. > Просто вопрос: а с каким именно продуктом Вы работали? > (действительно интересно)
C FastObjects .NET — писал небольшой проектик, в нем уже FastObjects
использовался.
Здравствуйте, Serginio1, Вы писали:
S> Все, что применимо в обычном программировании, применимо и для БД. Реально можно обходится и без индексов для подчиненных коллекций если ее применять ввиде двухнаправленного связного списка, а начало и конец держать в родителе (при этом запись может содержать относительное место в БД например номер записи). При этом всиавка,Clear() вообще простая операция.
Дело в том, что речь идет о двунаправленной связи. И если ты делаешь в коллекции Clear(), то необходимо еще учтановить в null все ссылки с противоположной стороны, то есть в возможно большом количестве объектов.
V>Я же русским языком сказал, что в ячейках хеш-таблицы хранятся сортированные индексы, в которых всегда поиск NLog(N). V>Я все-таки буду писать подобную хеш-таблицу для второго дотнета (нужна самим подобная), учитывая твое замечание, предусмотрю в конструкторе фабрику для создания сортированных индексов в ячейках таблицы. Т.е., если будут подозрения плохое хеширование, можно подать фабрику для B+ индексов в ячейках. По умолчанию будет простой сортированный массив, в котором опять же трудоемкость не более NLog(N).
Таких хэш таблиц много, но опять же ты упрешься в неопределенность размера индекса и в итоге получишь гибрид хэш таблицы с Б+ деревом в каждой ячейке. Б+ деревья сами по себе очень универсальны и особенно подходят для неопределенного размера. Другое дело, что для больших структур лучше делать Б+ дерево на их хэшах со сравнением при выборе диапозона поискового хэша с искомым значением.
Кстати разница в поиске не столь огромна для Б+ деревьев и хэш таблиц. На практике всего в 4 раза http://gzip.rsdn.ru/article/alg/tlsd.xml
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>> Все, что применимо в обычном программировании, применимо и для БД. Реально можно обходится и без индексов для подчиненных коллекций если ее применять ввиде двухнаправленного связного списка, а начало и конец держать в родителе (при этом запись может содержать относительное место в БД например номер записи). При этом всиавка,Clear() вообще простая операция.
S>Дело в том, что речь идет о двунаправленной связи. И если ты делаешь в коллекции Clear(), то необходимо еще учтановить в null все ссылки с противоположной стороны, то есть в возможно большом количестве объектов.
То бишь упираемся в GC . Но пятьже все зависит от организации данных. Возможно держать для каждой записи некий список ссылающихся объектов, а в ссылающихся объектах держать не только ссылку, но и адрес в этом списке, для быстрого удаления при смене ссылки.
Но это так фантазии не слишком продуманные
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>>Дело в том, что речь идет о двунаправленной связи. И если ты делаешь в коллекции Clear(), то необходимо еще учтановить в null все ссылки с противоположной стороны, то есть в возможно большом количестве объектов.
S> То бишь упираемся в GC . Но пятьже все зависит от организации данных. Возможно держать для каждой записи некий список ссылающихся объектов, а в ссылающихся объектах держать не только ссылку, но и адрес в этом списке, для быстрого удаления при смене ссылки.
Неа. Я не про это вовсе. Здесь же речь идет о кэшировании объектов базы данных. Вот это "возможно большое количество объектов" может быть вообще не подгружено в кэш. И что тогда делать? Тупой вариант — это подгрузить их все, изменить в каждом поле, и сохранить эти изменения обратно на диск. Но, это плохой вариант.
S>Неа. Я не про это вовсе. Здесь же речь идет о кэшировании объектов базы данных. Вот это "возможно большое количество объектов" может быть вообще не подгружено в кэш. И что тогда делать? Тупой вариант — это подгрузить их все, изменить в каждом поле, и сохранить эти изменения обратно на диск. Но, это плохой вариант.
Я вообще противник кэширования объектов, либо только в одной транзакции. В сложных системах один из лучших вариантов, является много версионных читателей, один экслюзивный писатель. Re[20]: Объектно-ориентированные БД: основные принципы, орга
Здравствуйте, Alexey Rovdo, Вы писали:
AR>А почему бы просто не подождать до тех пор, пока они не подгрузятся в кэш по какой-либо иной надобности? А пока просто оставить специальную метку на месте удаленного объекта. Т.е. ссылки редактировать не сразу, а только по мере обращения к соответствующим объектам?
Здравствуйте, Serginio1, Вы писали:
S> Я вообще противник кэширования объектов, либо только в одной транзакции. В сложных системах один из лучших вариантов, является много версионных читателей, один экслюзивный писатель. Re[20]: Объектно-ориентированные БД: основные принципы, орга
Здесь вроде речь идет о движке СУБД, а не о ORM или других надстройках. Сам то движок должен как-то кэшировать для выполнения запросов и update'ов, хранимые процедуры (методы) должны как-то работать. Не с диском же напрямую.
Здравствуйте, Alexey Rovdo, Вы писали:
AR>А почему бы просто не подождать до тех пор, пока они не подгрузятся в кэш по какой-либо иной надобности? А пока просто оставить специальную метку на месте удаленного объекта. Т.е. ссылки редактировать не сразу, а только по мере обращения к соответствующим объектам?
Здесь еще одна хитрость в том, как эти данные хранятся на диске. Если двунаправленная связь храниться на диске тоже в двух местах, т.е. со стороны каждого из связываемых объектов, то и обновлять придется оба конца. Независимо от того, были все объекты подгружены в кэш или не были.
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>> Я вообще противник кэширования объектов, либо только в одной транзакции. В сложных системах один из лучших вариантов, является много версионных читателей, один экслюзивный писатель. Re[20]: Объектно-ориентированные БД: основные принципы, орга
S>Здесь вроде речь идет о движке СУБД, а не о ORM или других надстройках. Сам то движок должен как-то кэшировать для выполнения запросов и update'ов, хранимые процедуры (методы) должны как-то работать. Не с диском же напрямую.
Прошу прощения, как то потерял нить. Я это о своем эфимерном движке. Ну а с диском помоему уже давно никто не работает при кэшированных страницах. Просто доступ к ним возможенн только при своей реализации.
Еще раз прошу прощения за высказывания в невпопад.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Alexey Rovdo, Вы писали:
AR>А почему бы просто не подождать до тех пор, пока они не подгрузятся в кэш по какой-либо иной надобности? А пока просто оставить специальную метку на месте удаленного объекта. Т.е. ссылки редактировать не сразу, а только по мере обращения к соответствующим объектам?
Тут встанет другая проблема. Транзакционный механизм с их savepoint's.
Здравствуйте, Alexey Rovdo, Вы писали:
AR>Что то вы не так поняли. Я не имел ввиду никакого нарушения транзакционной целостности. Просто внутренние механизмы ООСУБД вовсе не обязаны физически удалять с диска (исправлять) те элементы, которые мы удалили. Достаточно пометить этот элемент как удаленный, а дальше — работа GC, который может исполняться асинхронно вне транзакции. То же самое и с исправлением ссылок. Если после поднятия ссылки (уже в другой задаче) оказывается, что она указывает на помеченный как удаленный элемент, то без уведомления приложения СУБД сама может обнулить соответсвующую ссылку и передать дальше уже null, а объект на диске исправить (вписать нул в хначение ссылки). Это очень похоже на то, как в FastObjects работает механизм версионности. Например, если мы исправили описание класса и удалили один из его атрибутов, то это вовсе не значит, что СУБД тут же перелопатит всю базу и изменит записи всех объектов данного класса (хотя мы и можем заставить ее сделать это). Вместо этого она будет править хранимые объекты только по мере их очередного редактирования, автоматически переводя их в новую версию при сохранении.
В данном случае мы подразумеваем, что можем выловить некорректную ситуацию (независимо от типа доступа) еще на уровне обработки метаданных. Но если у нас метаданные не затронуты. В результате мы получаем запрос, в котором мы должна учитывать, что информация о удаленной ссылки не лежит именно в данном объекте. Там проблемы начнутся нехилые.
Что касается транзакционного механизма. Как примерно работает нормальный (я бы сказал самый распространенный) механизм транзакции. Все изменения производятся в кольцевом логе. После определенного момента — происходит сброс изменений на диск (savepoint). После этого лог можно перезаписывать. Система достаточно проста и выдерживает отключение питания. У нас получается несколько неприятная вещь. С одной стороны, часть ссылок уже нормализована, а часть нет. Как это отразится на функционировании восстановления, с ходу не скажу, но то что надо что-то делать, вполне понятно.
Очень интересует вопрос функционирования GC для ООБД. То бишь, в персистентном хранилище(большом и медленном). Не мог бы кто-нибудь "плюнуть" какую-нибудь ссылочку. Должна быть занятная вещь.
Здравствуйте, eao197, Вы писали:
GZ>>В данном случае мы подразумеваем, что можем выловить некорректную ситуацию (независимо от типа доступа) еще на уровне обработки метаданных. Но если у нас метаданные не затронуты. В результате мы получаем запрос, в котором мы должна учитывать, что информация о удаленной ссылки не лежит именно в данном объекте. Там проблемы начнутся нехилые.
E>Я думаю, что здесь проблем нет. Просто такая обработка лежит на отдельном уровне абстракции. Где-то выше кэша, но ниже планировщика запросов (или какая там архитектура будет).
Смотри что получается. У нас есть запрос вместе с where exist(object.reference) Три варианта:
1. Мы просматриваем объект на который ссылаемся. Плохо. Избыточное чтение.
2. Мы кладем это в запрос. Плохо. В результате у нас получается очень неприятное условие и длинное.(в ОРМ — более чем криминально, но для ООДБ этот вариант я считаю наименее плохим)
3. Мы смотрим после выполнения запроса. Плохо. Избыточное чтение.
GZ>>Что касается транзакционного механизма. Как примерно работает нормальный (я бы сказал самый распространенный) механизм транзакции. Все изменения производятся в кольцевом логе. После определенного момента — происходит сброс изменений на диск (savepoint). После этого лог можно перезаписывать. Система достаточно проста и выдерживает отключение питания. У нас получается несколько неприятная вещь. С одной стороны, часть ссылок уже нормализована, а часть нет. Как это отразится на функционировании восстановления, с ходу не скажу, но то что надо что-то делать, вполне понятно.
E>Здесь я так же не вижу проблемы. Главное, чтобы надежно сохранился объект-ссылка, в котором установлен признак, что она уже некорректна.
Я тоже явно не вижу. Но тут нужно сохранять не ссылку, а состояние GC. Что может быть очень накладным и сложным процессом.(сходу не скажу).
GZ>>Очень интересует вопрос функционирования GC для ООБД. То бишь, в персистентном хранилище(большом и медленном). Не мог бы кто-нибудь "плюнуть" какую-нибудь ссылочку. Должна быть занятная вещь.
E>У Константина Книжника в Goods подобный механизм был реализован. Он даже в своей диссертации какую-то теорему доказывал на эту тему. Если не ошибаюсь о том, что объект можно удалять из БД, если он не достижим по ссылкам из других объектов.
Тут несколько другой GC. Второй тип ссылочной целостности, в котором при удалении объекта — все ссылки на него обнуляются. Хотя в принципе это можно организовать более простым способом чем в goods. При наличии метаданных, ессно.
Здравствуйте, eao197, Вы писали:
E>У Константина Книжника в Goods подобный механизм был реализован. Он даже в своей диссертации какую-то теорему доказывал на эту тему. Если не ошибаюсь о том, что объект можно удалять из БД, если он не достижим по ссылкам из других объектов.
GC в FastObjects t7 работает фактически по данному принципу (там только всякие настроечки имеются).
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, eao197, Вы писали:
GZ>>>В данном случае мы подразумеваем, что можем выловить некорректную ситуацию (независимо от типа доступа) еще на уровне обработки метаданных. Но если у нас метаданные не затронуты. В результате мы получаем запрос, в котором мы должна учитывать, что информация о удаленной ссылки не лежит именно в данном объекте. Там проблемы начнутся нехилые.
E>>Я думаю, что здесь проблем нет. Просто такая обработка лежит на отдельном уровне абстракции. Где-то выше кэша, но ниже планировщика запросов (или какая там архитектура будет). GZ>Смотри что получается. У нас есть запрос вместе с where exist(object.reference) Три варианта: GZ>1. Мы просматриваем объект на который ссылаемся. Плохо. Избыточное чтение. GZ>2. Мы кладем это в запрос. Плохо. В результате у нас получается очень неприятное условие и длинное.(в ОРМ — более чем криминально, но для ООДБ этот вариант я считаю наименее плохим) GZ>3. Мы смотрим после выполнения запроса. Плохо. Избыточное чтение.
Торможу что-то к вечеру. Давай еще раз. Вот так я себе представлял объект-ссылку:
class One_side
{
ref< Another_side > m_ref;
}
class Another_side
{
ref< One_side > m_ref
}
// А это физическое представление ссылки.
class Ref_image
{
bool m_is_valid;
oid m_one_side;
oid m_another_side;
}
Когда в объекте One_size обнулятся ссылка One_side.m_ref в соответствующем объекте Ref_image сбрасывается флаг m_is_valid.
Когда каким-то образом Another_side извлекается из БД, сама СУБД автоматически тянет объект Ref_image и проверяет его m_is_valid. Если m_is_valid сброшен, то в Another_side автоматически обнуляется m_ref. И только после этого Another_side идет в дальнейшую обработку на стороне СУБД. Т.е., в моем представлении такими вещами должен заниматься уровень сериализации.
Проблемы в таком подходе, имхо, возникают, если объектиков Ref_image будет куча. Т.е. возврат к тому вопросу, с которого stalcer начинал.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Торможу что-то к вечеру.
Я тоже сейчас не Энштейн. E>Давай еще раз. Вот так я себе представлял объект-ссылку: E>
E>class One_side
E>{
E> ref< Another_side > m_ref;
E>}
E>class Another_side
E>{
E> ref< One_side > m_ref
E>}
E>// А это физическое представление ссылки.
E>class Ref_image
E>{
E> bool m_is_valid;
E> oid m_one_side;
E> oid m_another_side;
E>}
E>
E>Когда в объекте One_size обнулятся ссылка One_side.m_ref в соответствующем объекте Ref_image сбрасывается флаг m_is_valid. E>Когда каким-то образом Another_side извлекается из БД, сама СУБД автоматически тянет объект Ref_image и проверяет его m_is_valid. Если m_is_valid сброшен, то в Another_side автоматически обнуляется m_ref. И только после этого Another_side идет в дальнейшую обработку на стороне СУБД. Т.е., в моем представлении такими вещами должен заниматься уровень сериализации.
Возможно я тоже чего-то не врубился. Но я описывал ситуацию, в которой удаляется сам объект. Приведу слова Alexey Rovdo:
Если после поднятия ссылки (уже в другой задаче) оказывается, что она указывает на помеченный как удаленный элемент, то без уведомления приложения СУБД сама может обнулить соответсвующую ссылку и передать дальше уже null, а объект на диске исправить (вписать нул в хначение ссылки).
Или я чего-то не понял?
E>Проблемы в таком подходе, имхо, возникают, если объектиков Ref_image будет куча. Т.е. возврат к тому вопросу, с которого stalcer начинал.
Именно. Либо мы начинаем обнулять (или приводить в состояние удален) ссылки при удалении объекта (по типу как ты ты привел), или мы получаем то, что я описал.
Здравствуйте, GlebZ, Вы писали:
GZ>Тут несколько другой GC. Второй тип ссылочной целостности, в котором при удалении объекта — все ссылки на него обнуляются. Хотя в принципе это можно организовать более простым способом чем в goods. При наличии метаданных, ессно.
Это скорее не GC, а метафора слабой ссылки — weak reference. По моему скромному имху, ООСУБД должна предоставлять оба типа ссылок. Чтобы не принуждать владельца любой ссылки к постоянной проверке ее валидности, и в то же время не рисковать "пришпилить" мусор при помощи невинной записи в логе или еще чего нибудь.
Кстати, если реализовывать эту метафору в стиле .Net, т.е. предоставить единственную реализацию класса слабой ссылки, то можно существенно улучшить производительность обнуления. Благодаря тому, что вся семантика этого класса совершенно точно известна еще при проектировании СУБД, можно схитрить при синхронном обнулении ссылок и не поднимать в память "честные" объекты, ограничившись прямой модификацией дисковых страниц. Кроме того, можно использовать кластеризацию по target ссылки, благодаря чему обнуление затронет минимум страниц (а с учетом потрясающей компактности этих ссылок много страниц потребуется обновлять только при удалении очень популярных объектов).
Не хуже решается и вопрос асинхронного обнуления — проверить содержащийся OID на валидность при каждом снятии ссылки не так уж и дорого. Единственное но — обращение к Target, которое на первый взгляд не должно вызывать побочных эффектов, в такой системе все-таки "трогает" ссылку, со всеми вытекающими последствиями для транзакции, читающей эту ссылку.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, GlebZ, Вы писали:
GZ>>Тут несколько другой GC. Второй тип ссылочной целостности, в котором при удалении объекта — все ссылки на него обнуляются. Хотя в принципе это можно организовать более простым способом чем в goods. При наличии метаданных, ессно. S>Это скорее не GC, а метафора слабой ссылки — weak reference. По моему скромному имху, ООСУБД должна предоставлять оба типа ссылок. Чтобы не принуждать владельца любой ссылки к постоянной проверке ее валидности, и в то же время не рисковать "пришпилить" мусор при помощи невинной записи в логе или еще чего нибудь.
Я когда-то делал два типа ссылок: soft_ref и hard_ref. Объясню на примерах. Пусть объект A ссылается на объект B с помощью seft_ref, а объект C ссылается на объект D с помощью hard_ref. Объекты B и D не могут быть удалены, пока существуют объекты A и C. Если же удаляется объект A, то объект B остается в базе, просто для него уменьшается счетчик ссылок. Если же удаляется объект C, то с ним вместе удаляется и объект D (при условии, что на него кроме A больше никто не ссылается). Т.е. hard_ref -- это отношение владения (D без С не может существовать), а soft_ref -- это соседские отношения.
Sinclair, это не возражение против твоего поста. Просто я разсказал, как я когда-то делал.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Ну и я пожалуй внесу свою лепту. Когда-то хотел (и сейчас хочу) сделать некоторую фичу для ORM.
В объект введено состояние логически удален. Вообще, удивительно. Это настолько часто используется в бизнес-приложениях, но ни одна тулза (известная мне) не предоставляет средств (кроме каких-то визуальных тулзов для Delphi).
И к этому присобачена разного вида ссылки и такая проверка ссылочной целостности при удалении.
Тип ссылки 1. Если существует объект на который ссылается, то объект не может быть удален.
Тип ссылки 2. Если существует объект на который ссылается, то объект может быть удален только логически
Тип ссылки 3. Если существует объект на который ссылается, то оба объекта удаляются вместе (логически или физически)
Поскольку при этом поднимается некий граф объектов, то скорости тут ждать не приходится. Но для обычных бизнес-приложений, скорость должна быть достаточна.
Здравствуйте, GlebZ, Вы писали:
GZ>В объект введено состояние логически удален.
Это состояние случайно не влечет за собой запрет ставить новые ссылки на этот объект? GZ>Вообще, удивительно. Это настолько часто используется в бизнес-приложениях, но ни одна тулза (известная мне) не предоставляет средств (кроме каких-то визуальных тулзов для Delphi). GZ>И к этому присобачена разного вида ссылки и такая проверка ссылочной целостности при удалении. GZ>Тип ссылки 1. Если существует объект на который ссылается, то объект не может быть удален. GZ>Тип ссылки 2. Если существует объект на который ссылается, то объект может быть удален только логически GZ>Тип ссылки 3. Если существует объект на который ссылается, то оба объекта удаляются вместе (логически или физически)
Че-то я уже начинаю тормозить. Завтра перечитаю
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, vdimas, Вы писали:
V>>Я же русским языком сказал, что в ячейках хеш-таблицы хранятся сортированные индексы, в которых всегда поиск NLog(N). V>>Я все-таки буду писать подобную хеш-таблицу для второго дотнета (нужна самим подобная), учитывая твое замечание, предусмотрю в конструкторе фабрику для создания сортированных индексов в ячейках таблицы. Т.е., если будут подозрения плохое хеширование, можно подать фабрику для B+ индексов в ячейках. По умолчанию будет простой сортированный массив, в котором опять же трудоемкость не более NLog(N). S> Таких хэш таблиц много, но опять же ты упрешься в неопределенность размера индекса и в итоге получишь гибрид хэш таблицы с Б+ деревом в каждой ячейке. Б+ деревья сами по себе очень универсальны и особенно подходят для неопределенного размера. Другое дело, что для больших структур лучше делать Б+ дерево на их хэшах со сравнением при выборе диапозона поискового хэша с искомым значением. S> Кстати разница в поиске не столь огромна для Б+ деревьев и хэш таблиц. На практике всего в 4 раза http://gzip.rsdn.ru/article/alg/tlsd.xml
Для моего "гибрида" я получал разницу в десятки раз. Это ощутимо и это причина пользовать именно ее.
На самом деле, если функция кеширования достаточно удачна (а я как разработчик практически всегда этого добиваюсь), то прирост быстродействия пропорционален двоичному логарифму размера хеш-таблицы. (по крайней мере, стремится к такой пропорциональности)
Далее, в подавляющем большинстве случаев у меня суррогатные ключи — это последовательность целых значений. Генератор ключей построен так, чот при удалении ключи не пропадают, а запоминаются в кеше и повторно применяются при следующих созданиях объектов. Т.е. при многократных удалениях/созданиях объектов у меня практически нет "дыр" в последовательности и мои хранилища являются иделальным вариантом для простейшей ф-ии кеширования X = key % cache_size.
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, Sinclair, Вы писали:
S>Точно. Все верно описал.
S>Если речь идет о большой системе, если она модульная, и если пишется совместно многими программистами, то двунаправленные связи в домейн-модели, если они вшиты в доменные классы будут представлять из себя большой геморрой, так как будут вносить много зависимостей между модулями на логическом уровне доменной модели. И что самое противное — циклических зависимостей.
S>И вторая проблема, как ты правильно написал, если есть две подсистемы и их объекты никак не связаны, а связываются они только в третьей подсистеме, то велика вероятность, что эта связь в достаточно большом количестве подзадач задействована не будет и ее было бы неправильно засовывать в объекты, чисто с точки зрения производительности/памяти.
S>Вот и возникает мысль о том что объявлять связи нужно отдельно от классов доменных объектов. И даже может не только объявлять, но и кэшировать как-то в отдельных структурах, а не при помощи перекрестных ссылок (коллекций ссылок). S>Только вот я тут думаю уже на протяжении полугода как бы это сделать. Уж больно все сложно получается. Так — что у меня крыша съезжает .
хе... а у нас вполне работает...
могу выложить чать инфраструктуры и пообсуждать:
В моей системе есть дестрипторы — которые суть описатели и фабрики объектов обпределенного типа,
есть storages — суть хранилища объектов, описываемых неким десткриптором,
есть линки, которые кешируют лишь факт наличия связи (все работает по lazy loading).
Есть сами сущности, которые суть данные, и есть роперы над сущностями, которые временно создаются для выполнения каких-либо сложных операций над данными или для представления сущности на удаленном клиенте.
Обращаю внимание на метод Init данного враппера. В этом методе мы запрашиваем у объектов-линков специальные интерфейсы, через которые перечисляем подчиненные объекты.
Ниже приведены основные интерфейсы:
/// <summary>
/// Summary description for IEntityFactory.
/// </summary>public interface IEntityFactory
{
/// <summary>
/// Creates clone of entity
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>object CloneEntity(object entity);
/// <summary>
/// Creates uninitialized entity object
/// </summary>
/// <returns></returns>object CreateEntityInstance();
}
public interface IEntityDescriptor : IEntityFactory {
/// <summary>
/// TypeCode of Entity type
/// </summary>
TypeCodeT TypeCode { get; }
/// <summary>
/// Type of entity
/// </summary>
Type EntityType { get; }
/// <summary>
/// Type of wrapper
/// </summary>
Type WrapperType { get; }
/// <summary>
/// Short friendly entity name (most usual just class name without namespaces)
/// </summary>string Name { get; }
/// <summary>
/// List of entity fields
/// </summary>
EntityFieldCollection FieldList { get; }
/// <summary>
/// Extracts entity ID
/// </summary>
/// <param name="entity">target entity</param>
/// <returns>Object ID of entity</returns>
ObjectIdT ExtractEntityId(object entity);
/// <summary>
/// Extracts entity Name
/// </summary>
/// <param name="entity">target entity</param>
/// <returns>name of entity object</returns>string ExtractEntityName(object entity);
/// <summary>
/// Extracts entity description
/// </summary>
/// <param name="entity">target entity</param>
/// <returns>description of entity object</returns>string ExtractEntityDescription(object entity);
/// <summary>
/// Creates wrapper for given entity instance
/// </summary>
/// <param name="entityRef">instance of entity ref to wrap</param>
/// <returns>Wrapper object</returns>
EntityWrapper GetWrapper(IEntityRef entityRef);
/// <summary>
/// Extracts NamedObjectId structure from entity object
/// </summary>
/// <param name="entity"></param>
/// <returns>NamedObjectId entity representation</returns>
NamedObjectId ToNamedObjectId(object entity);
/// <summary>
/// Extracts NamedObjectId structure from entity object
/// </summary>
/// <param name="entities">collection of entities</param>
/// <returns>NamedObjectId[] array of entities representations</returns>
NamedObjectId[] ToNamedObjectIdList(ICollection entities);
EntityValue[] ConvertToEntitiesValues(ICollection entities);
void SetFieldValue(object entity, int fieldId, Var val);
Var GetFieldValue(object entity, int fieldId);
/// <summary>
/// Entity comparer
/// </summary>
IComparer Comparer { get; }
}
public interface IEntityStorage : IEntityRefFactory, ISynchronizable {
/// <summary>
/// Entity meta-information provider and helper
/// </summary>
IEntityDescriptor Descriptor { get; }
/// <summary>
/// Extracts full list of entities
/// </summary>
/// <returns>full list of entities</returns>
ICollection GetEntityList();
/// <summary>
/// Extracts selected list of entity
/// </summary>
/// <param name="filterObjectIds">filtered IDs of entities</param>
/// <returns>filtered list</returns>
ICollection GetEntityList(ObjectIdT[] filterObjectIds);
/// <summary>
/// Get cache entry for entity ID.
/// By default - with no cache behaviour implementation
/// </summary>
/// <param name="objectId">ID of entity</param>
/// <param name="loadObject">if true the load object imediatelly</param>
/// <returns>Cache entry for given entity ID</returns>
IEntityRef GetCacheEntry(ObjectIdT objectId, bool loadObject);
/// <summary>
/// Get cache entry for entity
/// By default - with no cache behaviour implementation
/// </summary>
/// <param name="entity">ID of entity</param>
/// <returns>Cache entry for given entity ID</returns>
IEntityRef GetCacheEntry(object entity);
/// <summary>
/// Get cache entries
/// </summary>
/// <param name="entityCollection"></param>
/// <returns></returns>
ICacheEntryCollection GetCacheEntries(ICollection entityCollection);
/// <summary>
/// Get cache entries
/// </summary>
/// <param name="ids">IDs of objects</param>
/// <param name="initialize">initialize cache entry</param>
/// <returns></returns>
ICacheEntryCollection GetCacheEntries(ObjectIdT[] ids, bool initialize);
/// <summary>
/// Initializes cache entry if needed
/// </summary>
/// <param name="entry">cache</param>void InitCacheEntry(IEntityRef entry);
/// <summary>
/// Extract related objects from DB or cache
/// </summary>
/// <param name="childStorage">related links</param>
/// <param name="parentObjId">master object ID</param>
/// <returns>list of related objects</returns>
ICollection GetChildEntities(IEntityStorage childStorage, ObjectIdT parentObjId);
// TODO: Remove!!!
ICollection GetChildEntities(TypeCodeT childTypeCode, ObjectIdT parentObjId);
/// <summary>
/// Creates new entity object in storage
/// initializes key fields
/// </summary>
/// <returns></returns>
IEntityRef CreateNewEntity();
/// <summary>
/// TODO: Remove!!!
/// </summary>
/// <param name="parentStorage"></param>
/// <param name="masterObjectId"></param>
/// <returns></returns>
IEntityRef CreateRelatedEntity(IEntityStorage parentStorage, ObjectIdT masterObjectId);
/// <summary>
/// Deletes entity from storage
/// </summary>
/// <param name="entityId">id of entity</param>
/// <param name="transaction">transaction context</param>void DeleteEntity(EsdTransaction transaction, ObjectIdT entityId);
/// <summary>
/// Save entity wrapper
/// </summary>
/// <param name="transaction"></param>
/// <param name="wrapper"></param>void SaveEntityWrapper(EsdTransaction transaction, EntityWrapper wrapper);
/// <summary>
/// Collection of related IEntityRef entries
/// </summary>
/// <param name="link"></param>
/// <param name="masterObjectId"></param>
/// <returns></returns>
ICollection GetRelatedEntities(IMasterDetailLink link, ObjectIdT masterObjectId);
/// <summary>
/// Register link on storage
/// </summary>
/// <param name="link"></param>void RegisterLink(LinkBase link);
IMasterDetailLink GetMasterDetailLink(TypeCodeT childTypeCode);
}
/// <summary>
/// Collection of IEntityRef
/// </summary>public interface ICacheEntryCollection : ICollection {
/// <summary>
/// Storage
/// </summary>
IEntityStorage EntityStorage { get; }
/// <summary>
/// initialized tag
/// </summary>bool Initialized { get; }
}
public interface IMasterDetailLink {
void Clear();
/// <summary>
/// Master entity meta-info
/// </summary>
IEntityStorage MasterStorage { get; }
/// <summary>
/// Detail entity meta-info
/// </summary>
IEntityStorage DetailStorage { get; }
/// <summary>
/// Returns detail links
/// </summary>
/// <param name="masterObjectId">master object links</param>
/// <returns>Detail links collection</returns>
IDetailEntitiesCollection GetDetail(ObjectIdT masterObjectId);
}
/// <summary>
/// Detail links bag definition
/// </summary>public interface IDetailEntitiesCollection : ICollection, IEntityListProvider {
/// <summary>
/// add detail linked object
/// </summary>
/// <param name="childEntityRef">added child entity</param>void Add(IEntityRef childEntityRef);
/// <summary>
/// Key of Master Object (ObjectIdT)
/// </summary>
ObjectIdT MasterObjectId { get; }
/// <summary>
/// Master entity meta-info
/// </summary>
IEntityStorage MasterEntityStorage { get; }
/// <summary>
/// Detail entity meta-info
/// </summary>
IEntityStorage DetailEntityStorage { get; }
/// <summary>
/// Creates new detail-side linked (!!!) object
/// </summary>
/// <returns>newly created object</returns>
IEntityRef CreateDetailEntity();
/// <summary>
/// Accesor to linked object by ID
/// </summary>
/// <param name = "detailObjectId">ID of linked object to extract</param>object this[ObjectIdT detailObjectId] { get; }
/// <summary>
/// Remove child object (or delete in pure MD-link)
/// </summary>
/// <param name="transaction"></param>
/// <param name="childObjectId"></param>void RemoveChild(EsdTransaction transaction, ObjectIdT childObjectId);
}
public interface IEntityRef {
ObjectIdT ObjectId { get; }
object Entity { get; set; }
}
/// <summary>
/// Entity reference
/// </summary>public class EntityRef : IEntityRef {
object _entity;
ObjectIdT _id;
public EntityRef(ObjectIdT id, object entity) {
_id = id;
_entity = entity;
}
public EntityRef(ObjectIdT id) {
_id = id;
}
public ObjectIdT ObjectId {
get { return _id; }
}
public object Entity {
get { return _entity; }
set { _entity = value; }
}
}
/// <summary>
/// Weak entity reference
/// </summary>public class WeakEntityRef : WeakReference, IEntityRef {
ObjectIdT _id;
public WeakEntityRef(ObjectIdT id, object entity)
: base(entity, false) {
_id = id;
}
public ObjectIdT ObjectId {
get { return _id; }
}
public object Entity {
get {
if (IsAlive)
return Target;
return null;
}
set { Target = value; }
}
}
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, eao197, Вы писали:
GZ>Тут IMHO не все так однозначно. Изменение ссылки точно такая-же логгируемая операция, как и любое изменение объекта. То есть, при изменении, мы должны записать об этом в конце транзакции в лог. Попробуем рассмотреть оба варианта с точки зрения работы лога и транзакций. GZ>В первом случае мы получаем, что при окончании транзакции мы сохраняем записи всем скопом в лог, и у нас при этом они кладуться в одну или несколько последовательных страниц. GZ>Во втором случае, у нас в случае если транзакция read-only, мы вынуждены открыть ее (а я думаю лучше по соседству другую) как updatable. Но при этом, непонятна длительность этой транзакции, и количество данных которое должно быть сохранено существенно меньше чем размер страницы.
Я тоже думаю, что лучше другую. И сразу же ее зафиксировать.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, eao197, Вы писали:
E>>Я когда-то делал два типа ссылок: soft_ref и hard_ref. Объясню на примерах. Пусть объект A ссылается на объект B с помощью seft_ref, а объект C ссылается на объект D с помощью hard_ref. Объекты B и D не могут быть удалены, пока существуют объекты A и C. Если же удаляется объект A, то объект B остается в базе, просто для него уменьшается счетчик ссылок. Если же удаляется объект C, то с ним вместе удаляется и объект D (при условии, что на него кроме A больше никто не ссылается). Т.е. hard_ref -- это отношение владения (D без С не может существовать), а soft_ref -- это соседские отношения. S>Фактически, это третий тип ссылок. Трабл с ним я вижу в том, что не вполне понятно, что произойдет в случае наличия еще и soft_ref ссылок на объект D. Понятно, что само наличие двух hard_ref ссылок на один объект в такой системе — косяк. А вот что делать с софт ссылками — непонятно.
В моем случае наличие soft-ссылок на объект просто запрещало удаление объекта (т.е. связи были однонаправленными). Т.е., если в моем примере объект B имел soft-ссылку на объект D, то удаление C становилось невозможным (т.к. невозможно было удалить объект D).
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
GZ>>Тут IMHO не все так однозначно. Изменение ссылки точно такая-же логгируемая операция, как и любое изменение объекта. То есть, при изменении, мы должны записать об этом в конце транзакции в лог. Попробуем рассмотреть оба варианта с точки зрения работы лога и транзакций. GZ>>В первом случае мы получаем, что при окончании транзакции мы сохраняем записи всем скопом в лог, и у нас при этом они кладуться в одну или несколько последовательных страниц. GZ>>Во втором случае, у нас в случае если транзакция read-only, мы вынуждены открыть ее (а я думаю лучше по соседству другую) как updatable. Но при этом, непонятна длительность этой транзакции, и количество данных которое должно быть сохранено существенно меньше чем размер страницы.
E>Я тоже думаю, что лучше другую. И сразу же ее зафиксировать.
А надо ли это вообще оформлять как транзакцию (с логами и всем вытекающим)? Ведь в данном случае оба состояния (до и после) совершенно равнозначны и со стороны приложения не различимы.
Здравствуйте, Alexey Rovdo, Вы писали:
AR>Здравствуйте, eao197, Вы писали:
GZ>>>Тут IMHO не все так однозначно. Изменение ссылки точно такая-же логгируемая операция, как и любое изменение объекта. То есть, при изменении, мы должны записать об этом в конце транзакции в лог. Попробуем рассмотреть оба варианта с точки зрения работы лога и транзакций. GZ>>>В первом случае мы получаем, что при окончании транзакции мы сохраняем записи всем скопом в лог, и у нас при этом они кладуться в одну или несколько последовательных страниц. GZ>>>Во втором случае, у нас в случае если транзакция read-only, мы вынуждены открыть ее (а я думаю лучше по соседству другую) как updatable. Но при этом, непонятна длительность этой транзакции, и количество данных которое должно быть сохранено существенно меньше чем размер страницы.
E>>Я тоже думаю, что лучше другую. И сразу же ее зафиксировать.
AR>А надо ли это вообще оформлять как транзакцию (с логами и всем вытекающим)? Ведь в данном случае оба состояния (до и после) совершенно равнозначны и со стороны приложения не различимы.
Имхо, любую модификацию БД нужно оформлять через транзакцию. Чтобы можно было восстановиться после сбоя. Ведь здесь речь идет не столько о логическом состоянии, которое видно для приложения, сколько о физической целостности страниц хранилища.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Имхо, любую модификацию БД нужно оформлять через транзакцию. Чтобы можно было восстановиться после сбоя. Ведь здесь речь идет не столько о логическом состоянии, которое видно для приложения, сколько о физической целостности страниц хранилища.
Так то оно так. Но может ли в обсуждаемом случае нарушиться физическая целостность? Смоделируйте ситуацию. Возможно здесь хватит и более простых мер?
Кстати, возвращаясь к упоминавшемуся мной ранее механизму версионности в FastObjects. Так вот там read-only операции не влияют на объект — он переформатируется в новую версию только тогда, когда приложение его редактирует.
Здравствуйте, vdimas, Вы писали:
S>> Кстати разница в поиске не столь огромна для Б+ деревьев и хэш таблиц. На практике всего в 4 раза http://gzip.rsdn.ru/article/alg/tlsd.xml
V>Для моего "гибрида" я получал разницу в десятки раз. Это ощутимо и это причина пользовать именно ее. V>На самом деле, если функция кеширования достаточно удачна (а я как разработчик практически всегда этого добиваюсь), то прирост быстродействия пропорционален двоичному логарифму размера хеш-таблицы. (по крайней мере, стремится к такой пропорциональности)
V>Далее, в подавляющем большинстве случаев у меня суррогатные ключи — это последовательность целых значений. Генератор ключей построен так, чот при удалении ключи не пропадают, а запоминаются в кеше и повторно применяются при следующих созданиях объектов. Т.е. при многократных удалениях/созданиях объектов у меня практически нет "дыр" в последовательности и мои хранилища являются иделальным вариантом для простейшей ф-ии кеширования X = key % cache_size.
Это все понятно и полностью согласен. Но есть одна вещь которая все эти предположения напрочь убивает, а именно кэш процессора, сброс кэша и доступ к медленной памяти. Кстати заметь, что в этом тесте моя хэш таблица в 1.8 раз быстрее нетовской. Но от коллизий ни куда не уйти и нужно нарываться на новый поиск, а данные могут находиться вне кэша.
Опять же для Б+ деревьев при определенном использовании верхнии уровни находятся в кэше процессора, поэтому поиск в них на больших данных оазывается быстрее, чем бинарный поиск в массиве с проинлайнниным компаратором, в отличие от компараторов Б+ (TLSD).
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Alexey Rovdo, Вы писали:
AR>Здравствуйте, eao197, Вы писали:
E>>Имхо, любую модификацию БД нужно оформлять через транзакцию. Чтобы можно было восстановиться после сбоя. Ведь здесь речь идет не столько о логическом состоянии, которое видно для приложения, сколько о физической целостности страниц хранилища.
AR>Так то оно так. Но может ли в обсуждаемом случае нарушиться физическая целостность?
Легко. Мы же сейчас обсуждаем ситуацию, когда некий объект A ссылается на объект B посредством объекта связи C (A -> C -> B). При этом, после удаления или обнуления ссылки в B объект A продолжает ссылаться на C. При первом обращении к A нам нужно автоматически поднять объект C, увидеть, что он помечен как удаленный и сделать две вещи: удалить ссылку на C из A и удалить объект C.
Рассмотрим ситуацию с изменением A. Мы обнуляем в A один (или даже несколько) атрибутов. При последующей сериализации образ A может "поплыть", т.е. быть серьезно изменившимся по сравнению с исходным образом A. И дальше все зависит от того, как изменения укладываются в БД. Если A записывается на свое старое место, то может оказаться, что A размещался на нескольких страницах хранилища (вот такой он большой, например). Тогда сбой между записями страниц оставит БД в неверном состоянии. Если же новое значение A записывается в другое место хранилища с соответствующей корректировкой цепочки занятых блоков/страниц, то сбой между записью A и корректировкой блоков так же оставит БД в ошибочном состоянии. Аналогичные проблемы могут быть и при удалении объекта C из БД.
AR>Кстати, возвращаясь к упоминавшемуся мной ранее механизму версионности в FastObjects. Так вот там read-only операции не влияют на объект — он переформатируется в новую версию только тогда, когда приложение его редактирует.
А до этого в нашем случае СУБД будет вынуждена каждый раз тянуть за A объект C только для того, чтобы убедиться, что эта ссылка уже не действительна? А если объект A вообще больше никогда не будет извлекаться из БД для изменения, а только для чтения?
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>А до этого в нашем случае СУБД будет вынуждена каждый раз тянуть за A объект C только для того, чтобы убедиться, что эта ссылка уже не действительна? А если объект A вообще больше никогда не будет извлекаться из БД для изменения, а только для чтения?
А тогда и нужен GC, который сделае всю работу асинхронно в моменты слабой загрузки системы.
Здравствуйте, Alexey Rovdo, Вы писали: AR>Кстати, возвращаясь к упоминавшемуся мной ранее механизму версионности в FastObjects. Так вот там read-only операции не влияют на объект — он переформатируется в новую версию только тогда, когда приложение его редактирует.
А как насчет ассоциативного запроса? Там разве не взводится Lazy Writer, который в фоновом режиме выполняет конверсию, а получение такого запроса переводит его в foreground?
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, GlebZ, Вы писали:
GZ>>В объект введено состояние логически удален. S>Это состояние случайно не влечет за собой запрет ставить новые ссылки на этот объект?
Скорее всего да. И вообще любое редактирование логически удаленного объекта — запретить. Вообще это только намерение. Я пока только уверен, что подобная система нужна. GZ>>Вообще, удивительно. Это настолько часто используется в бизнес-приложениях, но ни одна тулза (известная мне) не предоставляет средств (кроме каких-то визуальных тулзов для Delphi). GZ>>И к этому присобачена разного вида ссылки и такая проверка ссылочной целостности при удалении. GZ>>Тип ссылки 1. Если существует объект на который ссылается, то объект не может быть удален. GZ>>Тип ссылки 2. Если существует объект на который ссылается, то объект может быть удален только логически GZ>>Тип ссылки 3. Если существует объект на который ссылается, то оба объекта удаляются вместе (логически или физически) S>Че-то я уже начинаю тормозить. Завтра перечитаю
Вся эта шняга предназначена для стандартной ситуации. У нас есть живой объект, который ссылается на некоторый справочник. Значение из этого справочника — убили. В результате, при показе этого живого объекта значение логически удаленного показывается, но его нельзя присвоить другому объекту. Точно так-же он недоступен и при редактировании самого справочника. При потери последней ссылки на логически удаленный объект — объект должен удалиться(что зачастую в реальных решениях не делается). Но предполагаю, поскольку это предназначается для ORM, то при удалении будет генерится очень нехилый select или набор select'ов для проверки как возможности удаления, так и для удаления связанных. Возможно здесь подсчет ссылок был бы полезней, если бы не его проблемы и требования того, что ORM можно напустить практически на любую базу.
Здравствуйте, GlebZ, Вы писали:
GZ>Но предполагаю, поскольку это предназначается для ORM, то при удалении будет генерится очень нехилый select или набор select'ов для проверки как возможности удаления, так и для удаления связанных.
Ну, вот RDBMS например этого почему-то не боятся. Delete всегда проверяет все foreign key. И ничего — вроде как-то живет. В основном благодаря тому, что FK — это всегда индекс; а также потому, что этих FK редко бывает много. Ну сослались на меня из десяти мест — это уже какая-то экзотика пошла.
Правда, в OODBMS тут есть некоторая тонкость, связанная с более слабой типизацией. В RDBMS у нас FK всегда попадает ровно в одну таблицу, а стало быть и в обратную сторону связей будет немного. А в ODBMS у нас ссылка может указывать на любого потомка. Так что это может привести к увеличению области сканирования: при использовании везде ссылок на System.Object придется при каждом удалении проверять абсолютно все ссылочные поля!
Без практики применения невозможно сказать, насколько проверка наличия ссылок на себя в типичной OODB дороже, чем в RDB. GZ>Возможно здесь подсчет ссылок был бы полезней, если бы не его проблемы и требования того, что ORM можно напустить практически на любую базу.
Сам по себе подсчет ссылок — всего лишь кэширование результатов поискового запроса. Этакая денормализация.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Alexey Rovdo, Вы писали: AR>>Кстати, возвращаясь к упоминавшемуся мной ранее механизму версионности в FastObjects. Так вот там read-only операции не влияют на объект — он переформатируется в новую версию только тогда, когда приложение его редактирует. S>А как насчет ассоциативного запроса? Там разве не взводится Lazy Writer, который в фоновом режиме выполняет конверсию, а получение такого запроса переводит его в foreground?
PTXX automatically registers changes in the class dictionary, but it does not change the objects in the
database. However, FastObjects allows you to read the objects from older or newer versions of the
class without changing the database. This is known as on-the-fly versioning, and is extremely useful in
environments where several versions of a class declaration can be in use at the same time. For example,
several programs developed at different times share the same database.
If you want to avoid the overhead of on-the-fly versioning, you can convert the objects to the new format
after you register a class. This can be done using one of the FastObjects administration tools, or by calling
thePtBase::VersAll()method.
FastObjects observes the same rules for on-the-fly versioning and for versioning objects in the database:
• If a new member is added to the class, the objects are initialized to zero.
• If a member is deleted from the class, the objects are removed. If you then store the versioned object or
version the entire database, this data is lost and cannot be recovered.
• If the relative positions of classmembers change, the objects are reformatted to reflect the new positions.
• If the data type, array size, etc. of a member changes and the name remains the same, the old value is
converted to the new type (e.g., a short can be converted to a long).
• Pointers can be changed to ondemand references on-the-fly, or vice versa.
• The type of set can be changed from lset or hset to another set type on-the-fly.
AR>>А почему бы просто не подождать до тех пор, пока они не подгрузятся в кэш по какой-либо иной надобности? А пока просто оставить специальную метку на месте удаленного объекта. Т.е. ссылки редактировать не сразу, а только по мере обращения к соответствующим объектам?
S>Дык, я же именно про это и говорю.
1. Status of deleted — When you delete an object, it is automatically marked for deletion from its database at
the next commit.
2. When an application requests an object, VERSANT first searches the object cache, then the server cache for
the database to which the object belongs, and then the database itself.
Здравствуйте, GlebZ, Вы писали:
GZ>А вот программеры боятся. Каждая вторая база не удаляет ничего. Возьми хотя бы RSDN для примера. А все потому, что логика сложная получается.
Это не имеет отношения к теме GZ>При удалении System.Object всегда можно определить его действительный тип. Это сократит количество задействованных ссылок.
Нет, ты ошибаешься.
Представь себе, что у меня в системе 10 классов. В каждом определено от 1 до 3 ссылок типа System.Object. В средем это получается по 2 ссылки на объект.
Итак, допустим у меня есть миллион этих объектов.
Я пытаюсь удалить один из них.
Независимо от того, какого он типа, на него может указывать любая из двух миллионов ссылок, разбросанных по 12 экстентам. Поэтому нам придется выполнить сканирование двенадцати ращличных индексов для проверки, нет ли там нас. GZ>Но тут есть другое увеличение, в этом может участвовать не один объект а целый граф.
Верно подмечено. Дорогостоящая операция может получиться. GZ>Я все больше о ней думаю... Но пока это все только прикидки, когда делать буду (и что получится в результате) пока не знаю.
Ну, статьи про GC в OODB в сети вроде имеются... Дойдут руки — будем почитать
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Независимо от того, какого он типа, на него может указывать любая из двух миллионов ссылок, разбросанных по 12 экстентам. Поэтому нам придется выполнить сканирование двенадцати ращличных индексов для проверки, нет ли там нас.
А кто мешает организовать аналог FK для OODB ????
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinclair, Вы писали:
S>Представь себе, что у меня в системе 10 классов. В каждом определено от 1 до 3 ссылок типа System.Object. В средем это получается по 2 ссылки на объект. S>Итак, допустим у меня есть миллион этих объектов. S>Я пытаюсь удалить один из них. S>Независимо от того, какого он типа, на него может указывать любая из двух миллионов ссылок, разбросанных по 12 экстентам. Поэтому нам придется выполнить сканирование двенадцати ращличных индексов для проверки, нет ли там нас.
Имхо, когда речь идет о двунаправленных связях, я бы задумался о хранении при объекте информации о том, кто на него ссылается.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Serginio1, Вы писали: S> А кто мешает организовать аналог FK для OODB ????
Гм. Никто не мешает. Мы про него и говорим.
Попробую повториться еще раз: В RDBMS нельзя сделать ссылку "на что угодно". Она может ссылаться только в конкретную таблицу. Благодаря этому можно ожидать разумного среднего количества кандидатов в обратные ссылки. В OODBMS ссылка может быть полиморфной. Это может привести к деградации производительности при динамическом подсчете обратных ссылок, принятом в RDB.
З.Ы. Все это — теория. Степень "актуального полиморфизма", которая определяет эту "нечеткость" области значения ссылки, зависит от конкретной OODB.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Serginio1, Вы писали: S>> А кто мешает организовать аналог FK для OODB ???? S>Гм. Никто не мешает. Мы про него и говорим. S>Попробую повториться еще раз: В RDBMS нельзя сделать ссылку "на что угодно". Она может ссылаться только в конкретную таблицу. Благодаря этому можно ожидать разумного среднего количества кандидатов в обратные ссылки. В OODBMS ссылка может быть полиморфной. Это может привести к деградации производительности при динамическом подсчете обратных ссылок, принятом в RDB. S>З.Ы. Все это — теория. Степень "актуального полиморфизма", которая определяет эту "нечеткость" области значения ссылки, зависит от конкретной OODB.
Сделать можно, только разруливать придется на клиенте или через дополнительные таблицы к каждому типу обрабатываемые через триггеры в зависимости от типа.
Опять же опыт 1С. Строятся дополнительные таблицы. (правда поиск там ссылочной целосности идет полным сканированием по метаданным).
Для OODB будет зависеть от реализации, там выбор действий намного больше.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinclair, Вы писали:
S>Гм. Никто не мешает. Мы про него и говорим. S>Попробую повториться еще раз: В RDBMS нельзя сделать ссылку "на что угодно". Она может ссылаться только в конкретную таблицу. Благодаря этому можно ожидать разумного среднего количества кандидатов в обратные ссылки. В OODBMS ссылка может быть полиморфной. Это может привести к деградации производительности при динамическом подсчете обратных ссылок, принятом в RDB. S>З.Ы. Все это — теория. Степень "актуального полиморфизма", которая определяет эту "нечеткость" области значения ссылки, зависит от конкретной OODB.
Однако тут есть некоторое дополнение. Поскольку ссылка содержит oid экземпляра объекта, то на полиморфизм можно положить. Если ее проверять навигационным способом, то это не должно занимать много времени (у нас проверка объекта — это время на доступ по хешу, и нам в принципе нужно узнавать, есть объект или его нет). Но правда это верно только для двунаправленной связи. Возможно, можно даже запретить подобную ссылочную целостность для недвунаправленной связи как сверхтормозную.
29 апреля 2005 г. Компания Ленвендо проводит семинар "Современные технологии сохраняемости Java и .NET объектов";
Дата проведения семинара: 29 апреля 2005 г.
План семинара:
— Обзор современных технологий сохраняемости
— Обзор существующих решений
— ООСУБД – прозрачная сохраняемость объектов
— Системы масштаба предприятия, построенные с использованием технологий ООСУБД
— Инструментарий объектно-реляционного отображения (O/R Mapping Tools)
— Versant Open Access JDO <BR>- Versant Open Access .NET
— Системы масштаба предприятия, построенные с использованием технологий объектно-реляционного отображения
Место проведения:
Санкт-Петербург, Измайловский пр., дом 14 (вход с 7-ой Красноармейской)
Насколько я понял, IMasterDetailLink у вас — это дескриптор для ассоциации (так же как и IEntityDescriptor — дескриптор для ентити)? Так?
Интересно, как именно он реализован внутри!
В каком формате в кэше храняться связи.
Как работают методы IDetailEntitiesCollection.Add и IDetailEntitiesCollection.RemoveChild.
Если есть кэш связей, то какой алгоритм удаления этих связей из кэша.
Какой алгоритм подгрузки связей (вместе с объектами или отдельно).
Какой алгоритм сохранения измененных связей — вместе с объектами или отдельно.
Сколько памяти (в ссотвествии в вашим форматом хранения) в кэше занимает одна связь (не ассоциация целиком, а именно связь).
Насколько ваш формат менее эффективен чем хранение в самих объектах перекрестных ссылок (коллекций ссылок). Т.е. насколько он медленее и почему. И насколько он требует больше памяти.
Как вы отслеживаете ссылочную целостность с учетом изменений (связей), сделанных в кэше.
PS: Понятия ассоциации и связи я использую из UML. Если вы вдруг не в курсе, то там отношение между ассоциацией и связью, аналогичны отношению между классом и объектом. То есть связь, в таком понимании — это instance ассоциации. Это, чтобы нам не запутаться .
Здравствуйте, BaZa, Вы писали:
BZ>В VDS так оно и есть (описание здесь)
BZ>1. Status of deleted — When you delete an object, it is automatically marked for deletion from its database at BZ>the next commit. BZ>2. When an application requests an object, VERSANT first searches the object cache, then the server cache for BZ>the database to which the object belongs, and then the database itself.
Неа. Опять непонятки по теме разговора.
Например, есть два хранимых класса:
class A
{
List<B> objectsB;
}
class B
{
A objectA;
}
Например, в базе есть один объект класса A и к нему привязаны 1000000 объектов класса B. То есть a.objectsB.Count == 1000000.
Так как я говорю про двунаправленные связи, то поля objectsB и objectA должны меняться синхронно, то есть если я сделаю:
a.objectsB.Clear();
То это значит, что все objectA у всех соответствующих объектов класса B должны автоматически поменяться на null. Я нигде не говорил про какое-то удаление объектов. При этой операции никакого удаления не проиходит. Объекты класса B не удаляются, просто они перестают быть связанными с объектом 'a'.
Дык, вот если в кэше на момент выполнения Clear() был только объект 'a', то что делать-то, чтобы синхронно изменить поля objectA? Подгружать чтоли все соотвествующие объекты класса B. Или как ?
Здравствуйте, Alexey Rovdo, Вы писали:
AR>Таким образом в VDS двунаправленные ссылки фактически являются отдельными объектами, которые имеют структуру списка в случае one-to-many ссылок. А сами объекты с атрибутами-двунаправленными ссылками фактически содержат ссылки на объекты BiLink или на конкретные элементы списка внутри объекта BiLink. Удаление и редактирование основных объектов-контейнеров приводит к поднятию соответствующего объекта BiLink и проведению с ним неких манипуляций.
Во-во. "редактирование основных объектов-контейнеров приводит к поднятию соответствующего объекта BiLink" — Это как? То есть соотвествующие объекты (PObject) с другой стороны будут подгружены или нет. Чего-то непонятно написано.
AR>Но при этом второй (множество) связанный с ним по двунаправленной ссылке объект не затрагивается — изменяются только объекты BiLink.
Это как? Объект BiLink является же полем (т.е. частью состояния) хранимого объекта.
AR>Впрочем, я не такой уж эксперт по VDS и могу ошибаться. Пусть BaZa меня поправит, если это так.
Готов ответить практически на любые конкретные вопросы по bilink и/или рассказать с самого начала (тока это очень много).
Может быть пример выложить....
to AR: кстати в комментарий к Вашему рисунку:
есть объект А — у него есть bilink на другой объект Б, который не знает о том, что на него может ссылаться А.
Если бы было по-другому, то возникли бы проблемы при удалении. Поэтому обычно используется механизм, при котором bilink есть у обоих объектов (это улучшает скорость и работу с памятью). Т.е на 2 объекта 2 bilink в обе стороны.
Это на первый взгляд может показаться не очень удобно, но на практике дает значительный выигрыш.
Здравствуйте, BaZa, Вы писали:
BZ>Поэтому обычно используется механизм, при котором bilink есть у обоих объектов (это улучшает скорость и работу с памятью). Т.е на 2 объекта 2 bilink в обе стороны. BZ>Это на первый взгляд может показаться не очень удобно, но на практике дает значительный выигрыш.
Я насколько понимаю, bilink — это маленький объект — логический указатель на связь. Их по одному в каждом объекте.
Вопрос: есть ли что то общее, т.е. какой-то объект-связь, на который эти bilink'и указывают (в оперативной памяти (кэше), имеется ввиду). Или же это просто перекрестные ссылки.
И как реализован алгоритм измнения связей, т.е. как связь с обоих концов поддерживается в согласованном состоянии. Это больше интересует для случая, когда в одном из объектов мы меняем связь, а другой в это время в кэш еще не подгружен.
Здравствуйте, stalcer, Вы писали:
S>Я насколько понимаю, bilink — это маленький объект — логический указатель на связь.
просто указатель на связь
S>Их по одному в каждом объекте.
только если связь одна и она "одна к одному"
S>Вопрос: есть ли что то общее, т.е. какой-то объект-связь, на который эти bilink'и указывают (в оперативной памяти (кэше), имеется ввиду). Или же это просто перекрестные ссылки.
Скорее всего нет (непонятно зачем это нужно)
Билинк на одной стороне указывает на билинк на другой стороне
S>И как реализован алгоритм измнения связей, т.е. как связь с обоих концов поддерживается в согласованном состоянии.
// реализация функций bilink выглядит примернт так:#ifdef VPP_VTPCLS
DEFINE_BiLink_to_BiLink(Author,Document);
DEFINE_BiLinkVstr_to_BiLink(Folder,Document);
#endif
static int ___dummy1 = BiLink_to_BiLink(Author,Document)::
add(&Author::document,&Document::author);
// add - стандартный метод bilinkstatic int ___dummy2 = BiLinkVstr_to_BiLink(Folder,Document)::
add(&Folder::documents,&Document::folder);
S>Это больше интересует для случая, когда в одном из объектов мы меняем связь, а другой в это время в кэш еще не подгружен.
прелесть в том, что это можно сделать самому при необходимости.
Здравствуйте, BaZa, Вы писали:
BZ>просто указатель на связь
Пусть так.
S>>Их по одному в каждом объекте.
BZ>только если связь одна и она "одна к одному"
Конечно. Я это забыл уточнить.
S>>Вопрос: есть ли что то общее, т.е. какой-то объект-связь, на который эти bilink'и указывают (в оперативной памяти (кэше), имеется ввиду). Или же это просто перекрестные ссылки.
BZ>Скорее всего нет (непонятно зачем это нужно)
BZ>Билинк на одной стороне указывает на билинк на другой стороне
Ээээ. Билинк на одной стороне должен уж тогда указывать на объект с другой стороны, а не на билинк.
S>>И как реализован алгоритм измнения связей, т.е. как связь с обоих концов поддерживается в согласованном состоянии.
BZ>
BZ>// реализация функций bilink выглядит примернт так:
BZ>#ifdef VPP_VTPCLS
BZ>DEFINE_BiLink_to_BiLink(Author,Document);
BZ>DEFINE_BiLinkVstr_to_BiLink(Folder,Document);
BZ>#endif
BZ>static int ___dummy1 = BiLink_to_BiLink(Author,Document)::
BZ> add(&Author::document,&Document::author);
BZ>// add - стандартный метод bilink
BZ>static int ___dummy2 = BiLinkVstr_to_BiLink(Folder,Document)::
BZ> add(&Folder::documents,&Document::folder);
BZ>
Ну я же просил реализацию, а не заголовки .
S>>Это больше интересует для случая, когда в одном из объектов мы меняем связь, а другой в это время в кэш еще не подгружен.
BZ>прелесть в том, что это можно сделать самому при необходимости.
Меня интересует, вобщем, всего один вопрос: Как сделать так, чтобы не нужно было зря подгружать объекты при изменении связей.
Причем вся прелесть в том, что это должно работать автоматически.
Здравствуйте, stalcer, Вы писали:
S>Ээээ. Билинк на одной стороне должен уж тогда указывать на объект с другой стороны, а не на билинк.
"Снаружи" это выглядит как будто связывается два билинка, что внутри сказать сложно...
// чтобы определить билинки и отношения м/у ними, сначала определим bilinks:class B; // mandatory forward declarationclass A: public PObject {
public:
BiLink<B> toB; // attribute must be public
BiLinkVstr<B> B_Vstr; // attribute must be public
...
};
class B: public PObject {
public:
BiLink<A> toA; // attribute must be public
BiLinkVstr<A> A_Vstr; // attribute must be public
...
};
//определяем инициализацию этих связей
//типа:static int dummy1 =
BiLink_to_BiLink<A,B>::add(&A::toB,&B::toA);
static int dummy2 =
BiLinkVstr_to_BiLinkVstr<A,B>::add(&A::B_Vstr,&B::A_Vstr);
S>Меня интересует, вобщем, всего один вопрос: Как сделать так, чтобы не нужно было зря подгружать объекты при изменении связей. S>Причем вся прелесть в том, что это должно работать автоматически.
вообще это сделано Versant и они код этот не открывают (просто говорится, что это сделано хорошо).
Я понимаю, что вообще есть желание контролировать этот процесс, но, хотя add, remove, replace приведены выше, add_bilink_to, и все, что глубже закрыто...
дело в том, что лично я сам пишу больше на Java, (Versant VDS Java API) а там этого нет (и ненужно понятно почему)
Здравствуйте, BaZa, Вы писали:
S>>Меня интересует, вобщем, всего один вопрос: Как сделать так, чтобы не нужно было зря подгружать объекты при изменении связей. S>>Причем вся прелесть в том, что это должно работать автоматически.
BZ>вообще это сделано Versant и они код этот не открывают (просто говорится, что это сделано хорошо).
Вай, вай. Редиски. И в Bold этот код закрыт.
BZ>дело в том, что лично я сам пишу больше на Java, (Versant VDS Java API) а там этого нет (и ненужно понятно почему)
И почему же . Грузить лишние объекты всегда плохо.
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, BaZa, Вы писали:
S>>>Меня интересует, вобщем, всего один вопрос: Как сделать так, чтобы не нужно было зря подгружать объекты при изменении связей. S>>>Причем вся прелесть в том, что это должно работать автоматически.
BZ>>вообще это сделано Versant и они код этот не открывают (просто говорится, что это сделано хорошо).
S>Вай, вай. Редиски. И в Bold этот код закрыт.
Хм... если это действительно нужно (или просто очень хочется), то я могу попробовать (!) попростить показать код/объяснить как работает в деталях... (?)
BZ>>дело в том, что лично я сам пишу больше на Java, (Versant VDS Java API) а там этого нет (и ненужно понятно почему)
S>И почему же . Грузить лишние объекты всегда плохо.
Я имел ввиду, что в Java все построено на ссылках, поэтому подразумевается, что все такие механизмы нужно писать руками. (а может это просто дискриминация Java )
Здравствуйте, BaZa, Вы писали:
S>>Вай, вай. Редиски. И в Bold этот код закрыт.
BZ>Хм... если это действительно нужно (или просто очень хочется), то я могу попробовать (!) попростить показать код/объяснить как работает в деталях... (?)
Спасибо. Сильно напрягаться не стоит . А вообще, было бы интересно...
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, eao197, Вы писали:
E>>Нет, это проблема, только если выбранная коллекция требует для своего изменения полной загрузки себя в память. Например, если коллекция -- это вектор (непрерывная последовательность ссылок). А если коллекция -- это дерево, то в память нужно будет загрузить только вершину и те промежуточные узлы, которые ведут к модифицируемому узлу. И если речь идет о B+ дереве, например, то изятие одного элемента из дерева в несколько миллионов элементов потребует доступа всего к нескольким узлам (страницам) дерева.
S>Я о чем и говорю: коллекции в таком случае должны быть построены так, чтобы не нужно было подгружать ее вообще. Может быть даже просто запоминать все изменения в какой-то другой структуре, для того чтобы когда коллекция реально потребуется — загрузить ее (коллекцию) и скорректировать.
S>Тут еще фишка в том, что в большинстве случаев коллекции — маленькие и без разницы грузить ее всю или только часть. Это все равно одно обращение к базе. А вот если совсем не грузить , это да, это хорошо.
S>А еще может быть и обратная ситуация. Когда коллекция уже загружена, и из нее, например, удаляем объект. Или еще круче: делаем просто Clear(). И прикинь, что для этого необходимо будет подгрузить все соответствующие children объекты, чтобы изменить в них ссылки.
S>А ведь и та и другая ситуация может быть с равной вероятностью. И придумать алгоритм, который бы не грузил лишнее в обоих случаях — вот хитрая задачка.
Да нет, не очень хитрая.
Во-первых, подобные коллекции должны быть весьма специализированными коллециями.
Во-вторых, все коллекции подчиненных объектов одной связи (напр. документ->история) должны архитектурно отделяться в отдельную сущность. Т.е. если документу потребовалось обратиться к собственонй истории, то он должен попросить ее у внешней сущности.
Коллекция подчиненных ссылок может быть загружена (т.е. загружены как минимум все ключи), так и нет. В первом случае мы делаем изменения в коллекции и синхронизируем с БД, во втором — прямо пихаем изменения в БД (если не требуется предварительное чтение, а зачастую именно так).
Вопрос о синхронизации отпадает сам собой, если все эти коллекции управляются внешней сущностью, и являются, по-сути, лишь интерфейсом-фильтром к ней, т.е. не хранят собственную копию набора ключей/ссылок.
Примерно так у меня сделано в текущем нашем сервере приложений, очень удобно.
Дополнительные бенефиты:
— мы можем поднять всю историю по документу не поднимая сам документ (!!!)
— к внешним сущностям удобно прикручивать всякие навороты, например различные стратегии кеширования. Это принципиально трудноуправляемо (трудноконтролируемо), если сами объекты заведуют своими подчиненными коллекциями.
— в связях многие-ко-многим мы исключаем избыточность взаимных коллекций (берем во внимание, что конкретная колекция — это лишь интерфейс к сущности, обслуживающей связь, который "выглядит" как коллекция).
Здравствуйте, stalcer, Вы писали:
S>Ну я же просил реализацию, а не заголовки .
А зачем тебе реализация?
У меня, например, единица вхождения многие-ко-многим представлена примерно так:
(схематично)
class ManyToManyLinkEntry<T1, T2> {
ObjectRef<T1> obj;
Collection<T2> collection;
}
obj — это lazy ref, инициализируется ключем объекта (либо самим объектом, если тот уже в кеше)
collection — ничем не инициализируется, пустая. Инициализируется при первом обращении (это приведены private поля).
Предполагаю выложить свои наработки рядом с RFD, как высокоуровневое расширение, тогда и будет реализация
Здравствуйте, Михаил, Вы писали:
М>Здравствуйте, vdimas, Вы писали:
М>Это почти ObjectStore. С нормальным С++. И с транзакциями. М>Правда, с SQL там туговато...
Здравствуйте, vdimas, Вы писали:
V>Во-вторых, все коллекции подчиненных объектов одной связи (напр. документ->история) должны архитектурно отделяться в отдельную сущность. Т.е. если документу потребовалось обратиться к собственонй истории, то он должен попросить ее у внешней сущности.
Пусть так. Значит есть некий класс, который как бы является интерфейсом к ассоциации в целом. Т.е. позволяет создавать новые экземпляры ассоциации (т.е. связи), и удалять их. Т.е. связывать и развязывать объекты. Внутри этого класса есть глобальный список всех Entry. Так?
Каждая Entry — это связь.
Здесь можно по разному сделать:
1) Каждая Entry — это связь ровно между двумя объектами. Независимо от того, "один к одному", "один ко многим" или "многие ко многим".
2) Каждая Entry — это как ты написал здесь
. Т.е. (ключ + коллекция ключей) для один ко многим. Ну и соответственно (ключ + ключ) для один к одному. Или я неправильно понял?
V>Коллекция подчиненных ссылок может быть загружена (т.е. загружены как минимум все ключи), так и нет. В первом случае мы делаем изменения в коллекции и синхронизируем с БД, во втором — прямо пихаем изменения в БД (если не требуется предварительное чтение, а зачастую именно так).
Эээ. Я принципиально все изменения делаю в кэше. Сброс только потом, т.е. не сразу. Так что, как раз интересует, как это сделать, если коллекция не загружена.
V>Вопрос о синхронизации отпадает сам собой, если все эти коллекции управляются внешней сущностью, и являются, по-сути, лишь интерфейсом-фильтром к ней, т.е. не хранят собственную копию набора ключей/ссылок.
Т.е у тебя нет перектрестных ссылок в самих объектах. Но, какие-то ссылки в самих объектах есть? Например, ссылка на соответствующий Entry? Или же Entry ты ищешь ассоциативно, по id объекта.
V>- в связях многие-ко-многим мы исключаем избыточность взаимных коллекций (берем во внимание, что конкретная колекция — это лишь интерфейс к сущности, обслуживающей связь, который "выглядит" как коллекция).
Ну, имхо, в связях многие ко многим избыточности коллекций (если они сделаны в лоб, т.е. в обоих объектах по коллекции) как раз и нет.
Понимаешь, меня интересует не просто как сделать. Сделать-то я могу. Меня интересует алгоритм, который был бы эффективен по памяти и по скорости работы одновременно.
Вот, например, проанализируй, насколько твоя внешняя сущность (т.е. всякие Entry) занимает больше памяти, чем просто перекрестные ссылки. Особенно для случая "один к одному"?
И если в самих объектах ты не хранишь ссылок вообще (ну, там на Entry, например), то сколько индексов тебе надо построить в памяти, чтобы для всех возможных действий ассоциативный доступ к Entry (или к нескольким Entry) производился по индексу (хеш таблице).