Как стать автором
Обновить

Комментарии 98

Спрячь под хабракат.
done
Спасибо, это было интересно.
+1 топику, +1 в карму

Теперь можно переносить в коллективный блог. : )
Если есть какой тематический, сообщи плиз.

Интересно читать такие вещи.
Наверное SQL? Наверное стоит перед переносом подредактировать статью, литературный стиль, орфографию. Писалось "по быстренькому", поэтому не уверен что все всем понятно. Давайте сначала обсудим, а там посмотрим.
Мей би. Хотя тут мне более интересен не "чистый" SQL, а именно практические примеры реализации БД под конкретные нужды.
в SQL как раз последняя статья - о проектировании. и эта - является её дополнением.
Я не разработчик и не программист, "просто примусы починяю". : )
Сейчас думаю над небольшой БД для домашней бухгалтерии.

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

может кто до меня уже это делал


Это уж точно ))) Лучше всего готовую скачать. Есть неплохие варианты рублей за 300-500. Это всяко дешевле, чем Ваше время, потраченное на проектирование, на реализацию, а потом на перепроектирование и перереализацию задуманного. imho, конечно.
поддерживаю. еще лучше не скачать, а на годик подписаться в сети. те же деньги, но скорее всего получите лучше функционал и постоянное обновление.
Я конечно до мелочей докапываюсь, но лучше исправьте childs на children, так правильней.
Знаю. Но так короче :) Мне это замечание уже делали но менять так вот по быстрому api страшновато. Проект закончим, исправлю.
Если будете редактировать, неплохо бы заменить "childs" на "children" :)
я вот только всё никак понять не могу - зачем 2 поля под тип? блин... написал коммент и понял... :)
я за раскрытие темы. и за перемещение статьи в sql.
НЛО прилетело и опубликовало эту надпись здесь
По поводу типа связей, этот вопрос так же решен, но другим способом. Не хочется углубляться сейчас в подробности.
Насчет второго замечания, не согласен. Связи ограничивать не так уж необходимо. Но если так уж хочется, можно этот контроль реализовать программно, например с помощью файла конфигурации. Пока такой необходимости не было.
Кстати насчет "каждый должен через это пройти"
Опыт проектирования баз данных у меня достаточный, что бы отличить хорошее от плохого. Нужно понимать, что в данном случае БД это лишь место хранения связей объектов, для реализации паттерна "компоновщик". Вообще говоря, хранить связи можно где угодно, например в xml, просто в данном случае выбрана СУБД.
в XML проще выразить вложенность структур, а в "двухмерной" реляционной СУБД - нет. Вот и получается что дополнительные отношения (родитель-потомок, один к одному, один ко многим) выносятся в отдельные колонки и таблицы.
Угу-угу. Скажу более – вообще говоря и сами данные можно хранить где угодно. Скажем, в текстовых файлах на диске. О-очень гибко получается. Но почему-то используют СУБД. Наверное по привычке. С целью списания бюджетных средств на покупку дорогостоящих серверов баз данных. :-)

MikhailEdoshin абсолютно прав. Ваша идея имеет крайне опосредованное отношение к паттерну Composite. И по сути, она описывается одним предложением, а именно – вы вынесли хранение всех отношений предметной области один ко многим и многое-ко-многим в одну общую таблицу. Тем самым лишив сервер БД возможности полноценно поддерживать логическую целостность ваших данных (в данном случае ссылочную) и эффективно строить запросы. Поскольку логическую целостность поддерживать приходится, то вам придётся это делать руками в самом приложении. Заодно беспокоясь об изолированности транзакции и эффективности изменений данных в БД. Об эффективности написания и выполнения поисковых запросов теперь даже и упоминать неприлично.

Такие решения иногда приходится использовать, но для них нужны крайне веские основания. К примеру, если отношения между сущностями непрерывно меняются. Непрерывно, это не значит что несколько раз в месяц или год, это значит несколько раз в час или даже минуту. Скажем при проектировании некой детали в САПР системе. Но в таким случаях, как правило, и не применяют реляционные СУБД.
Я и не призываю использовать эту схему везде. Я в статье упомянул, что даже в системе выполненной по этой схеме, некоторые части реализованы по классической. Впрочем каждый имеет право на свое мнение. Некоторые до сих пор ООП не признают, и с радостью вам докажут чем ООП плох.
НЛО прилетело и опубликовало эту надпись здесь
Во-первых есть сиквенции. Зачем отдельная таблица я не понимаю. Во вторых есть мнение что такой подход станет узким местом при высокой нагрузке, ведь таблица на время записи блокируется, как впрочем и сиквенция.
Хотел в карму плюсик капнуть.. А оказалось уже. ;) Приятно когда не нужно выражать собственное мнение в комментариях когда оно уже выражено.

По поводу статьи - несколько не профессионально. сходя из моего опыта во всяком случае.
Ещё надо добавить, что такая схема сильно усложняет работу со стандартными ORM.
Ой, кстати. Все это реализованно с использованием Hibernate, и каждй компанент является одновременно и энтети. Так что совершенно не усложняет а наоборот дополняет.
а можно поподробнее? если нетрудно пару мапингов и классов )
НЛО прилетело и опубликовало эту надпись здесь
Что за книжка "Банды четырех"?
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
must read :)
НЛО прилетело и опубликовало эту надпись здесь
Я верю в то, что 64K хватит на всех ;)
спс за ссылки
640K
Попробую развить мысль. Если рассуждать подобным образом, то получится, что любую БД можно представить в виде одной таблицы.
Вот такие будут поля:
ObjectName - имя объекта
FieldName - имя свойства
Value - значение. Будет строковое, т.к. к строке можно привести любой тип.

В такой модели ровно те же плюсы, что и в предложенной для связей:
* Любые объекты можно добавлять произвольно, не перепроектируя БД
* Любые свойства тоже можно добавлять ничего не перепроектируя

Да и недостатки те же, ну, подумаешь, огромная таблица. Подумаешь, чуть сложнее запросы. Если где начнет тормозить - всегда можно выделить отдельную табличку для какого-нибудь конкретного объекта.

Уж не знаю, каким паттерном это назвать, но никому не кажется, что такой подход несколько ... эээ ... странный?
НЛО прилетело и опубликовало эту надпись здесь
Зато любое минимальное изменение требует большой затраты времени и сил при разработке. Чтоб все связи вычленить и т.п. Ну и технически, уверен, будут немереные затраты времени - для мало-мальски серьёзного запроса надо будет дцать раз связывать эту таблицу саму с собой. К тому же при строковых ключах...
EAV (Entity-Attribute-Value). Тоже применимый для некоторых задач паттерн. Только не для тех которые описаны в этой статье.
Мне одному кажется, что подобного вида решение хорошо подходит для слабоструктурированной информации, где нужно отслеживать связи данного конкретного объекта с чем-то, но при этом получение списка объектов, обладающих определенными свойствами, определенными связями или определенными связями с другими объектами с определенными свойствами (и т.д.) будет вызывать серьезные трудности?
Или еще кому-то приходила такая мысль? :)

Вообще, похоже на построение структуры БД типа "нейронная сеть".
> "нейронная сеть"
:)
граф
Когда я учился, понятия "объектный" еще почти не было :)
А вот БД типа "нейронная сеть" уже рассматривались (и, наверное, где-то были)
Я лично никакого принципиального отличия не заметил - смысл тот же. И минусы - те же.

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

2 Автор: а для чего такая реализация понадобилась? Постановка задачи?
Социальная сеть. Множество разнотипных объектов с причудливыми связями.
То есть, у вас можно создавать непредусмотренные вами связи прямо на лету? Пользователь взял и присоединил другого к себе не заложенными "я читаю" или "мой френд", а "я его папа"? И как они потом учитываются и обрабатываются?
Да
Это у нас хороший диалог получился :)

— И как они потом учитываются и обрабатываются?
— Да

Дадите ссылку посмотреть на все это в рабочем варианте?
Ссылку не дам. Внутреннюю реализацию там все равно не видно а расценят как пиар проекта. Не к чему здесь.
Я потом позже расскажу как обрабатывать разнотипные связи. В двух словах многие не поймут, тут подробно нужно рассказывать на примерах, а времени сейчас нет.
Тогда мы ждем продолжения :)
У некоторых появились вопросы и сомнения, надо предметно рассматривать.
Это хорошо что появились вопросы :) Значит статья своей цели достигла. Как появится время распишу все более подробно.
Если честно, я бы сделал немного по другому.
Cделал бы "базовую" таблицу
ConnectableItem, содержащую 2 поля: Id и Type
далее все таблицы, предполагающие связи ссылаются на эту таблицу таким образом что их первичный ключ так же является и внешним.
+ делается табличка для связей ConnectableItem to ConnectableItem.

Получится более типизированно и исключит возможность появления "кривых" данных.
Честно говоря не понял сути :)
В Вашей табличке для связей объектов идентификаторы не являются внешними ключами и теоретически могут ссылаться на несуществующие объекты.
Может возникнуть ситуация несогласованности данных что приведет к проблемам в работе кода.
Проблем быть не может, потому что для удаления объектов используется гарбиджколлектор. При удалении объекта, на самом деле объект из таблицы не удаляется, а удаляется лишь ссылка на него из твблицы GUID. Гарбиджколлектор (обычный джоб например) периодически удаляет объекты, на которые никто не ссылается. Само наличие лишних записей в БД не критично, это просто мусор который никому не мешает.
Странный подход, чреватый тормозами при работе ... гарбиджколлектора, как вы его называете, а так же при выборках из таблиц, где присутствуют ненужные данные
Мне было бы интересно узнать о подробностях реализации (разный тип связей и пр.), буду ждать продолжения.

Кстати в первом абзаце написано "писать боли".
Автор не совсем верно приводит описание паттерна "Composite". Далее цитата из "Шаблоны проектирования в Java. Марк Гранд".

Мотивы применения паттерна:

1. Есть сложный объект, который нужно представить в виде иерархии объектов, представляющей отношение "часть-целое".

2. Нужно свести к минимуму сложность иерархии "часть-целое", оставляя минимальным количество различных дочерних объектов, о которых должны быть осведомлены объекты дерева.

3. Не предъявляется никаких требований к большей части объектов из иерархии по их различию.

Пункты 2 и 3 накладывают серъёзные ограничения на объекты.
Паттерны вещь очень гибкая. Рассматривать их как догму большая ошибка.
НЛО прилетело и опубликовало эту надпись здесь
Например?
НЛО прилетело и опубликовало эту надпись здесь
Не стану спорить ибо это затянется. Скажу лишь что в MySQL нет контроля ссылочной целостности (по крайней мере для MyISAM) и это не мешает быть этой СУБД популярной. Наверное это о многом говорит.
НЛО прилетело и опубликовало эту надпись здесь
просто завел таблицу и все заработало?
НЛО прилетело и опубликовало эту надпись здесь
нет. код придется написать не тот же. хотя тут все зависит от реализации и инструментария.
НЛО прилетело и опубликовало эту надпись здесь
я так и думал что Хибернейт :) Сам его применяю сейчас. И главное, мои компоненты они полноценные хибернейтовские энтети! Их можно использовать и так и так. Независимо от аннотаций. Согласись это гибкость и это здорово.
НЛО прилетело и опубликовало эту надпись здесь
Насчет Вконтакте. Думаю что если бы они делали бы все по этой схеме, то развили бы свой сервис по функционалу раза в три быстрее, а оставшееся время кинули бы на оптимизацию узких мест и скорее всего большенство из них решили бы аппаратно, не переписывая кода. При этом куря всякие хорошие сигары и попивая сок лаймы новозеландской.
НЛО прилетело и опубликовало эту надпись здесь
вот, зацените, это почти про ваш случай: http://www.simple-talk.com/community/blogs/philfactor/archive/2008/05/29/56525.aspx

еще, по мелочи, GUID глобально уникален, что следует из его названия, так что дополнительные два поля с типами в таблице связей не нужны.
Нужны. Иногда нужно выбрать все связанные объекты всех типов а иногда только одного.
просто вы аргументировали их наличие вовсе не этим, а тем, что иначе объекты не различишь.
а так - получается та самая One True Lookup Table, про которую по ссылке написано.
Ну да, виноват. Тут просто двойное назначение так сказать, поэтому выбран вариант с 4-мя полями.
Кстати, спасибо за ссылку :)
Добавлю ещё пару ссылок, раз уж заговорили про One True Lookup Table и Entity-Attribute-Value.

http://tonyandrews.blogspot.com/2004/10/otlt-and-eav-two-big-design-mistakes.html
http://www.projectdmx.com/dbdesign/lookup.aspx
Это вы наступили на те грабли, которые разложили сами :)
Фактически, для решения вы вынесли в связь свойство объекта. Можно тогда и еще некоторые свойства вынести - как раз получим практически реляционную модель в перспективе :)

А не думали, что таким образом надо делать как раз очень маленькую часть? Сделать просто сквозные GIUD по всей базе, а те связи, которые требуют подобной гибкости, вынести в отдельное место? GUID_src, GIUD_dst, RelationType. Тип может иметь несколько полей, чтобы делать и "групповые" выборки? Все равно у вас вряд ли будет возможность связи типа "он мой папа" между юзером и записью в блоге :) То есть, тип связи определяет участников связи (кстати, может так же и определять "направленность": "он мой папа" - направленная связь, а "он мой брат" - двунаправленная).
Почему поля четыре? Ну 2 поля понятно, это ID связанных объектов, то есть их внешние ключи. Классическая схема - много-ко-многим. Но ведь только по ID нельзя уникально идентифицировать объект в пределах всей БД. В разных таблицах ID может повторяться (секвенция для каждой таблицы своя). Поэтому введено понятие типа объекта.

ГММММММММММММ, есть такое понятие как ЭНУМЕРАТОР) заводишь таблицу c парой полей одно из которых автоинкрементный айди другое откуда этот айди запросили и когда тебе нада получить новый ID инсертишь в эту таблицу и получаешь ID, а иначе мы в гораздо более жестких условиях, подобная архитектура весьма распространена, более того имеет смысл завести таблицу с названием типа NODES в которой хранить ноду для каждого экземпляра каждого типа контента если он может учавствовать в связях

вообще все это называется связь сущностей по графу, в отличии от менее гибких разновидностей графа таких как дерево или список
>есть такое понятие как ЭНУМЕРАТОР
есть такое понятие как сиквенция ;)
С такой структурой еще важно отслеживать отсутствие циклических ссылок. Если, конечно, их появление возможно на логическом уровне.
Что такое циклические сслыки? Много однонаправленных? Такое невозможно просто потому что в таблице GUID есть составной уникальный ключ. А ссылки туда/обратно часто наоборот полезны. Например пользователь может быть владельцем сообщества и сам же в нем и состоять.
Зависит от логического уровня. Например, если в такой структуре попробовать сохранить не сеть, а иерархию. При выборке всех дочерних элементов некоего элемента циклические ссылки все поломают.
ИМХО производительность будет сильно хромать. Эта таблица по опредлению узкое место в системе. Если связи между объектами постоянно меняются, то это выльется в каскад удалений и вставок. В многопользовательской системе это приведет к куче эксклюзивных блокировок. Придется держать огромное количество блокировок на строки в памяти, поскольку расширение на всю таблицу приведет к остановке работы, а это тоже ведет к падению производительности.
Какую база держит нагрузку при одновременной работе?
Этот вопрос решается разделением таблицы на несколько на уровне СУБД. Но я придерживаюсь принципа "преждевременная оптимизация это зло"
Интересно. Дайте две!

Особенно случаи, когда приходится пересаживаться на классику.
Пример когда без классики сложно: деревья NestedSets (только что придумал). Или, некоторые поисковые запросы, индексация. Некие части системы, к социальной сети не относящиеся, банерокрутилка например.

Люблю такую фразу "не доводите до фанатизма". Применимо ко всему :) Так что каждая концепция должна применяться только там, где она эффективна, а не там куда её в принципе возможно приткнуть.
Вставлю свои пять копеек, как раз сейчас занимаюсь поддержкой-разработкой продукта с подобной схемой связей.

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

Хочется дать совет, использовать эту таблицу только для связи между крупными сущностями (типа юзер-фотка), и стараться обходиться минимальным количеством типов таких связей.
По этой таблице можно построить всю структуру связей. Вообще всю! Проще то некуда! А вот логика связей по коду это на самом деле не лучший вариант.
Познавательная статейка, спасибо!
Но первые мысли после прочтения о производительности.
Что-то мне кажется если будет пару десятков тысяч записей, то начнутся жуткие тормоза.
На паре десятков, или даже сотен тысяч не начнутся точно. а вот на паре десятков миллионов думаю начнуться. но тут уде вступают в силу методы оптимизации. уверен чаще всего можно разрулить ситуацию даже не переписывая код.
Вот так вот. Года 2 назад обдумывал и переобдумывал подобную схему. Правда, не натыкался на этот паттерн. Очень хороша показалась для гибкого построения сайтов. Я даже диплом хотел по этой теме делать :) Но именно сайтов, а не приложений. Ибо медленно будет работать очень. Все дело в том, что на логическом уровне получается сетевая БД, то есть от чего уходили - к тому и пришли. А уходили ведь не зря. Сейчас для постороения подобных схем очень хорошо подойдут ООБД.
Паттерн Composite применительно к БД рассматривается среди прочих в 8 главе книги Роберта Мюллера «Базы данных и UML. Проектирование».

Только к вашей архитектуре OBJ-OBJ2OBJ он не имеет никакого отношения. Правильную критику про него пишут, если у вас в СУБД нет возможности наследования, со временем разобраться в данных будет сложнее и сложнее. Мы в Афише год назад переходили с такой схемы.
И как вам переход? Куда перешли? Афиша это социальная сеть с множеством разнотипного контента? Вы уж говорите тогда посушеству, было то, такие проблемы, сделали это, проблемы пропали и т.д.
А так многие программеры хотят с чего нибудь куда нибудь перейти. Непонятно с чего и непонятно куда только.
Это не социальная сеть пока, просто информационно справочный сайт.
Переход со сменой СУБД и изменением архитектуры БД был частной задачей в контексте смены архитектуры и платформы вообще. Общей задачей было обеспечить высокую скорость внесения изменений, потому была выбрана типа архитектура EAV (до меня). Я бы выбрал Core Entities & Hiers, т.к. в этой предметной области можно выделить 4 типа основных сущностей — Агенты (Люди), Произведения, Места и События. Все остальные можно описать как производные от них.

Кроме композитов Организации, Группы мест, Альбомы и Мероприятия, из-за которых меня и заинтересовал ваш пост. Нок сожалению, вы не об этом.
НЛО прилетело и опубликовало эту надпись здесь
А что за модель такая "Core Entities & Hiers"?
Я знаю о ней:
1. ты ее называешь Ключевые сущности и наследники
2. тебе она нравится в последнее время

Искал в Гугле и кроме как в твоих топиках не встретил такого названия.
Она официально называется иначе? Или ты сам придумал ;)
Я сейчас занимаюсь созданием каталога паттернов БД. "Официальных" названий, кроме EAV, вообще в этой сфере нет, конечно приходится придумывать.

Core Entities & Hiers является обобщением более специфической модели
http://databasedesignpatterns.org/index.… , которую предложил Joe Oats.
У этой архитектуры есть недостаток - два объекта могут быть связаны только одной связью.
Например, У фотографии могут быть два атрибута: кто добавил, и кто последний редактировал. Оба атрибута ссылаются на объект типа "пользователь", и оба этих пользователя могут быть одним человеком.
Добавляйте пятую колонку - тип связи. И таблицу - типы связей.
Хорошее замечание но я уже горил выше что этот вопрос решен другим путем. Но кук я пока не скажу, ибо в двух слава не скажешь, нужно на примерах.
Спасибо за статью, идея изложена вполне "прозрачно" :) Занятный эффект получился, мне предлагали для одной задачи использовать Composite, но после прочтения вашей статьи я понял что он там не подходит.
Как говорится - "негативный результат, тоже результат".
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории