Нет, я не буду рассказывать вам про MongoDB или ещё какую неполноценную «убийцу SQL». Статей на тему «SQL vs NoSQL» сравнивающих на самом деле реляционные субд с документными и так полно:
- MongoDB или как разлюбить SQL
- Реляционные базы данных обречены?
- NoSQL базы данных: понимаем суть
- Почему нужно 1000 раз подумать, прежде чем использовать noSQL
- SQL — гибок или почему я боюсь NoSQL
- NoSQL и Big Data – обман трудящихся?
- Чем поможет архитектору «NoSQL» и… поможет ли?
- Сравнение производительности MongoDB vs PostgreSQL. Часть I: No index
- Сравнение производительности MongoDB vs PostgreSQL. Часть II: Index
- Разбираем ACID по буквам в NoSQL
- Почему вы никогда не должны использовать MongoDB
- Почему мы выбрали MongoDB
- Недостатки RDBMS или RDBMS vs NoSQL
- Почему вы никогда не должны говорить «никогда»
- Еж с ужом в одной корзине, а также немного об отсутствии схемы
- Почему реляционные СУБД отлично подходят для стартапов: Пример из истории разработки мессенджера Kato
- Прощай, MongoDB, здравствуй, PostgreSQL
Но у большинства из них есть фатальный недостаток — авторы просто не в курсе, что моделей данных в СУБД есть куда больше, чем два упомянутых: от узкоспециализированных «словарей», то универсальных «графов». А популярные «реляционные» и «документные» находятся лишь где-то по середине между универсальностью и специализированностью.
Давайте сравним типичных представителей упомянутых типов СУБД (от большего к меньшему).
- Популярность: Oracle, MongoDB, Redis, HBase, OrientDB.
- Функциональность: OrientDB, Oracle, MongoDB, HBase, Redis.
- Скорость: очень сильно зависит от задачи, данных и реализации приложения. Я пересмотрел кучу бенчмарков, везде всё по разному.
SQL
Силы тысяч разработчиков направлены на то, чтобы довольно простые модели предметной области расположить в табличках так, чтобы это было быстро, гибко и не слишком сложно. Получается плохо. Пишутся огромные ORM фреймворки, зубодробительные SQL запросы, создаются огромные индексы, и дублируются данные.
В качестве примера приведу одну из типичных задач — работа с деревьями. Это может быть дерево комментариев, дерево разделов сайта, дерево тэгов. Деревьев очень много в предметных областях, но работая с реляционными СУБД их стараются избегать, так как работа с ними вызывает много боли.
Вот, сколько статей на одном только Хабре написано о проблеме, которая есть исключительно в РСУБД ввиду попытки упихнуть всё многообразие моделей предметной области в прямоугольные таблицы:
- Решение проблемы сортировки деревьев с помощью бинарного Materialized Path
- MS SQL: hierarchyid — иерархия по-новому
- Иерархические (рекурсивные) запросы
- Иерархические структуры данных и Doctrine
- Иерархические структуры данных и производительность
- Nested Sets + PostgreSQL TRIGGER
- Nested Sets + MySQL TRIGGER
- Full Hierarchy — иерархические структуры в базах данных
- Задача отображения деревьев в MySql. Способ отображения на хранимых процедурах
- Рекурсивные (Иерархические) запросы в PostgreSQL
- Реализация иерархии — объединение Adjacency List и Materialized Path через one-to-many
- Строим Nested Set дерево без рекурсии
- Степени — ключ к быстрой иерархии (пример на Django)
- Иерархические данные. В поиске оптимального решения
- Хранение деревьев в базе данных. Часть первая, теоретическая
- Денормализация деревьев
- Где смерть Кащеева?
- Nested Intervals и их реализация под Yii2
- Хранение иерархических структур. Симбиоз «Closure Table» и «Adjacency List»
- Cartesius — метод хранения и извлечения древовидных структур в реляционных базах данных или SQL деревья без червей и тараканов
Все решения сводятся к трём основным:
Таблица смежности. Потомок хранит ссылку на родителя. Тут не сохраняется порядок потомков (чтобы его сохранять нужно вводить дополнительную нумерацию, по которой сортировать, что замедляет как вставки так и выборки). Требуются рекурсивные запросы или денормализация таблиц смежностей.
Рекурсивный запрос поддерева:
WITH RECURSIVE Rec(id, parent, name, ord)
AS (
SELECT id, parent, name, ord FROM tree
UNION ALL
SELECT Rec.id, Rec.parent, Rec.name, Rec.ord
FROM Rec, tree
WHERE Rec.id = tree.parent
)
SELECT * FROM Rec
WHERE parent = 123
ORDER BY ord
Запрос поддерева по денормализованной таблице смежности:
SELECT navi.id , navi.name , navi.parent
FROM tree , navi
WHERE tree.ancestor = 123 AND navi.id = tree.node
ORDER BY ord
Материализованный путь. Потомок хранит номера всех предков (с сохранением их порядка). В худшем случае изменение иерархии приводит к обновлению данных всех узлов. При отсутствии соответствующего АПИ со стороны СУБД, требует фигурной манипуляции над строками, что не во всех случаях приемлемо по скорости. Не допускает вхождение одного потомка в несколько предков.
Запрос поддерева с использованием ordpath:
SELECT RowId, name FROM dbo.Tree WHERE @ParentId.IsDescendant(RowId) = 123
Вложенные интервалы. Каждый узел хранит два числа, которые определяют его точное положение в иерархии. В худшем случае изменение иерархии приводит к обновлению данных всех узлов. Не допускает вхождение одного потомка в несколько предков. Относительно сложные алгоритмы требуют повышенной аккуратности.
Запрос поддерева:
SELECT node.id, node.name
FROM tree AS node, tree AS parent
WHERE node.left BETWEEN parent.left AND parent.right
AND parent.id = 123
ORDER BY node.left;
Изменение деревьев гораздо сложнее, примеры кода можно найти по ссылкам выше.
Как видим, каждый тип решения имеет свои серьёзные ограничения на представимую им модель и эффективность разных типов запросов. А знаете почему нет такого большого числа обстоятельных статей про хранение деревьев, например, в графовых СУБД? Да потому, что там в принципе нет этих проблем, так как дерево — это частный случай графа. Так что вопрос «как же мне так исхитриться и сохранить в базу иерархию» в графовых базах вообще не стоит.
Запрос поддерева в графе:
SELECT name , parent FROM ( TRAVERSE child FROM #1:123 )
Да, нереляционные СУБД, не смотря на общее название «NoSQL», тоже могут поддерживать Structured Query Language, расширяя его своими операторами :-)
Многие SQL-профи тут обычно заявляют, мол деревья и тем более графы в предметных областях почти не встречаются. Но стоит немного выйти из зоны комфорта как тут же увидишь, что любая предметная область на самом деле представляет из себя граф — набор сущностей, между которыми есть разнообразные отношения. Если отношения эти 1-к-1 или хотя бы 1-ко-многим и при этом связывают лишь разнотипные сущности, то такие модели относительно легко ложатся на реляционную модель (если не учитывать разные виды джойнов с костылями в виде индексов). Но обычно всё не так. Во многих местах можно встретить отношения многие-ко-многим. В РСУБД для каждого такого отношения приходится заводить отдельную таблицу и несколько индексов к ней, а это усложнение архитектуры, раздувание данных и замедление работы с ними.
Некоторые, особо «передовые» программисты, предлагают хранить каждый тип моделей в своей СУБД. «Важные данные» в реляционных, деревья в графовых, а примитивные вообще в словарях. Но подобные подходы вида «всякой задаче свой инструмент» лишь добавляют головной боли (и как следствие багов разной степени тяжести) на тему консистентности данных в разных частях приложения.
Программная разработка — штука очень динамичная. Сегодня мастер у вас должен иметь одну профессию и вы просто даёте ему текстовое поле вписать её. Завтра потребуется, чтобы он мог указать профессию лишь из предложенных вами и вы даёте ему селект для выбора нужной, сохраняя id профессии в модель мастера (один-ко-многим). После завтра потребуется, чтобы он мог выбрать несколько профессий разом (многие-ко-многим). А через неделю вам срочно потребуется реализовать уже иерархический каталог профессий. В реляционной СУБД сложность каждого следующего перехода значительно превосходит предыдущий. С графовой — вы больше времени потратите на обсуждение, чем на реализацию. Так что при старте проекта имеет смысл брать наиболее гибкий инструмент, который позволит вам не терять темп разработки в процессе изменения бизнес требований (или лучшего понимания оных). Да, специализированные инструменты могут в некоторых случаях быть быстрее и именно в этих случаях, если в этом есть необходимость, стоит заниматься такого рода оптимизацией.
NoSQL
Часто толковые SQL-разработчики берут какую-нибудь MongoDB, о которой говорят на каждом углу, и пытаются примерить к своему проекту, но разобравшись с ней, недоумевающе крутят пальцем у виска. Бестолковые так и остаются на MongoDB, мирясь с отсутствием транзакций и отношений между документами, ради мифической скорости и возможности засунуть в документ любой json.
Нет, MongoDB даже среди документных СУБД — так себе, а уж в качестве альтернативы полноценным реляционным её в принципе нельзя рассматривать. А вот другая документная СУБД — OrientDB, бьёт реляционные по всем фронтам. Да, OrientDB на самом деле документная СУБД, которая, благодаря прямым ссылкам между документами позволяет описывать произвольные графы.
Давайте развеем несколько типичных мифов по поводу NoSQL, о котором судят по наиболее громким представителям — MongoDB и Redis:
1. Они не контролируют структуру записываемых пользователем данных. У отсутствия схем есть и плюсы (можно делать миграции данных в фоне, можно хранить не только кортежи примитивов), но и минусы (нужно внимательно следить что записываешь в базу, не эффективно хранятся данные). В OrientDB нашли разумный компромисс: вы можете указать схему и указанные там поля будут валидироваться в соответствии с ней при записи и не будут тратить место на имена полей, а не указанные валидироваться не будут, но будут занимать чуть больше места. Тут важно отметить, что изменение схемы не приводит к изменению самих документов — просто вы не сможете изменить их пока не приведёте к новому формату.
2. Они не удовлетворяют требованиям ACID (Атомарность, Согласованность, Изолированность, Надёжность). OrientDB этим требованиям удовлетворяет. Более того, она из коробки умеет партицирование и мастер-мастер репликацию, так что поддерживает в том числе и распределённые транзакции. При этом вы можете регулировать баланс между согласованностью и скоростью ответа:
writeQuorum определяет число узлов, которые должны подтвердить запись, прежде чем СУБД вернёт ответ, об успешном завершении транзакции.
readQuorum определяет число узлов, которые должны подтвердить актуальность данных, прежде чем данные вернутся в ответ на запрос.
По умолчанию все транзакции синхронны (дожидаемся ответа всех реплик), а чтение соответственно происходит без подтверждения актуальности (за её не надобностью в этом случае).
Примечательной особенностью является прозрачная поддержка map-reduce: если узел содержит не все данные, то он сам делает запрос к остальным узлам и сливает их ответы. Клиент может работать с партицированной базой данных как с цельной. Есть даже автобалансировщик, раскидывающий документы в кластеры по разным стратегиям.
3. Они не поддерживают SQL и предоставляют лишь простой специализированный API. OrientDB написана на Java и может быть интегрирована в другое Java приложение в качестве библиотеки. При этом есть несколько уровней публичного API:
Объектное. Низкоуровневый доступ к записям. Не рекомендуется к использованию, так как через него вы можете нарушить совместимость с двумя остальными API.
Документное. Тут вы имеете весь основной функционал основанный на документах и перекрёстных ссылках.
Графовое. Оно предоставляет дополнительные удобства для организации графов, но на практике всё же удобней оказалось использовать документное апи.
В качестве фронтенда к этим Java-API есть несколько библиотек, позволяющих писать запросы на разных языках (SQL, Gremlin, SPARQL).
Можно расширять функционал плагинами на Java. Собственно Lucene индекс и админка реализованы в качестве плагинов.
Так что не все NoSQL одинаково бесполезны :-)
NewSQL
Для сравнения подходов работы с графовой и реляционной СУБД, давайте создадим простейшую бизнес сущность — персону:
SQL
create table Persons (
name text,
age smallint
)
OSQL
create class Person
create property Person.name string
create property Person.age short
Тут всё просто и почти одинаково. Теперь добавим отношение «друзья»:
SQL
create table Persons_friends (
subject integer,
object integer
)
create unique index Persons_friends on Persons_friends ( subject , object )
OSQL
create property Person.friend linkset Person
Недостатки РСУБД уже начинают вылезать — нам потребовалась дополнительная таблица и уникальный индекс на ней. Индекс этот с одной стороны гарантирует, что у нас не будет дубликатов связей, а с другой позволяет быстро находить друзей по идентификатору пользователя.
Выведем основные данные о друзьях одного из пользователей:
SQL
select
Persons.rowid ,
Persons.name ,
Persons.age
from
Persons_friends as friends,
Persons
where
friends.subject = 123 ,
friends.object = Persons.rowid
OSQL
select expand( friend )
from #19:0
fetchplan *:-2 name:0 age:0
В РСУБД мы не можем хранить ссылки между записями — только их идентификаторы. Поэтому появляется хитрая конструкция, объясняющая как данные из одной таблицы соотносятся с другой. В графовой же мы просто разворачиваем ссылки.
А теперь найдём друзей его друзей:
SQL
select
Persons_1.rowid ,
Persons_1.name ,
Persons_1.age ,
Persons_2.rowid ,
Persons_2.name ,
Persons_2.age
from
Persons_friends as friends_1 ,
Persons_friends as friends_2 ,
Persons as Persons_1 ,
Persons as Persons_2
where
friends_1.subject = 123 ,
friends_1.object = Persons_1.rowid ,
friends_1.object = friends_2.subject ,
friends_2.object = Persons_2.rowid
OSQL
select expand( friend )
from #19:0
fetchplan *:-2
name:0
age:0
friend.name:0
friend.age:0
В РСУБД запрос заметно усложнился. По хорошему его нужно усложнить ещё сильнее, чтобы данные друзей первого уровня не дублировались для каждого друга второго уровня.
Продолжать можно долго, но суть, я думаю, уже ясна. Немного больше подробностей о различиях реляционного подхода и графового можно почерпнуть из презентации "How Graph Databases started the Multi Model revolution".
На последок отмечу, что в реляционных базах данные хранятся таблицами, но они крайне не эффективны при запросах, поэтому к ним добавляют автогенерируемое дерево — индекс. Причём индексы стараются делать покрывающими, то есть не требующими обращения к собственно таблицам за данными. Так вот, если вырезать таблицы и позволить индексному дереву иметь циклы, то мы получим ни что иное как графовую СУБД, где вся база данных — это один большой максимально эффективный индекс.
Хватит теории. Что на практике-то?
Последний год я занимался разработкой бэкенда для проекта SKEDDY (Поиск мастеров и запись к ним на услуги). Звучит вроде бы не сложно, однако число бизнес сущностей сейчас уже равно 20 (20 таблиц сущностей, если бы я использовал РСУБД): person, mail, phone, social, token, application, profession, service, meeting, assessment, album, image, notification, place, track, payment, article, aspect, facet, salon.
Между ними порядка 50 отношений, из них около 20 являются многими-ко-многим (ещё 20 таблиц смежностей и 20-40 индексов в РСУБД). В OrientDB же потребовался лишь один индекс для трансляции внешних айдишников во внутренние (внешние — человекопонятные и изменяемые, внутренние — персистентные и «странные»), один для фасетного поиска услуг плюс ещё пяток полнотекстовых и всё. Граф полностью нормализован, большинство запросов идут по прямым ссылкам между узлами, что позволяет делать глубокие выборки, не теряя в производительности и наглядности запросов.
Благодаря графовой модели данных, отображение на неё бизнес модели происходит легко и просто — единожды написанный простой обобщённый код для синхронизации с базой данных, позволил программировать в терминах бизнес сущностей без лишних забот об оптимизации запросов к СУБД. Собственно борьба с AngularJS отняла куда больше времени, но это уже совсем другая история…
Теперь о недостатках:
Документация довольно не плоха для основного функционала, но некоторые аспекты в ней отражены крайне слабо. Например, информацию о хуках приходится собирать по крупицам.
Больше что-то на ум ничего не приходит :-)
На этом всё. Кто заинтересовался, но что-то недопонял — не стесняйтесь задавать вопросы в комментариях.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Комментарии (327)
evnuh
18.09.2015 13:07+9Невероятно кульно, а теперь сравним размеры индексов и бенчмарки с банальными «прямоугольными табличками».
vintage
18.09.2015 13:22-13Вы думаете 40 частично денормализованных таблиц и 60 индексов на них будут весить меньше, чем один нормализованный граф с 20 классами узлов? :-)
eaa
18.09.2015 14:42То, что я думаю, часто не совпадает с тем, что есть на самом деле.
Приведите Ваши реальные сравнения, что сколько весит и каково время выполнения запросов в каждом случае, только после этого можно о чем-то говорить всерьез.vintage
18.09.2015 15:02Я же писал, всё сильно зависит от задачи и того как её решают. Выбирайте задачу, на которой будем сравнивать :-)
lair
18.09.2015 15:49+7Мы не хотим думать, просто дайте нам конкретные бенчмарки — конфигурация, ресурсы, скорость.
vintage
18.09.2015 16:10Ну ок, вот замеры, которые я проводил год назад на реальной базе: docs.google.com/spreadsheets/d/1GHwY63pOMlipNJgbRKAzXtlfa64shWagpXgdWTHiWUo/edit
У меня не стояла задача всесторонне исследовать производительность — просто показать, что оно как минимум не хуже и имеет смысл присмотреться.lair
18.09.2015 16:14+2Угу, вот прямо первая же метрика потрясает:
Размер на диске:
PostgreSQL: 600mb
OrientDB: 750mb
Вывод: объемы сопоставимы.
Разница в 25% — это для вас «сопоставимы».
Замеры скорости, сделанные разными инструментами — тоже доставляют.
Ну и, наконец, тестируете вы на конкретной задаче, которая для графов выгодна.vintage
18.09.2015 16:25-2Да, сопоставимы. 25% — это во первых не такая уж большая разница. А во вторых, там было много дубликатов связей из денормализованной SQL базы, которые графовую базу только раздували и замедляли.
Замеры скорости имеют фору у PostgreSQL ибо он напрямую общался с СУБД по бинарному протоколу, а не через JS прослойку в NodeJS.
Тестировал я на наиболее частом и сложном запросе. Вы бы не придирались :-) Если бы эти замеры доказывали неоспоримые преимущества OrientDB перед PostgreSQL по всем показателям на всех задачах, я бы пренепременно упомянул их в статье. Возьмите и проверьте на своих задачах и сделайте выводы. Сейчас же вы просто уверены, что «ничего не может быть быстрее моей любимой СУБД» и требуете от меня доказательств обратного.lair
18.09.2015 16:30+225% — это во первых не такая уж большая разница.
Когда у вас размеры БД измеряются терабайтами, вы будете иначе к этому относиться.
А во вторых, там было много дубликатов связей из денормализованной SQL базы, которые графовую базу только раздували и замедляли. [...] Замеры скорости имеют фору у PostgreSQL ибо он напрямую общался с СУБД по бинарному протоколу, а не через JS прослойку в NodeJS.
Это означает, что ваше тестирование некорректно.
Тестировал я на наиболее частом и сложном запросе.
Наиболее частом и сложном для вашей системы. А в «моей» системе таких запросов нет, зато дофига объемных выборок с отбором, группировкой и агрегатами.
Сейчас же вы просто уверены, что «ничего не может быть быстрее моей любимой СУБД» и требуете от меня доказательств обратного.
Вот еще. Я точно знаю, что есть СУБД, которые быстрее тех СУБД, которыми я пользуюсь. Заодно я знаю, благодаря чему это происходит, и что я теряю, чтобы приобрести эту скорость.vintage
18.09.2015 16:42Когда у вас размеры БД измеряются терабайтами, вы будете иначе к этому относиться.
С чего бы? Плюс-минус террабайт в таких масштабах погоды не делают. А погоду делают совсем другие метрики. Возможности масштабирования, например.
Это означает, что ваше тестирование некорректно.
Оно достаточно корректно для поставленной задачи.
Наиболее частом и сложном для вашей системы. А в «моей» системе таких запросов нет, зато дофига объемных выборок с отбором, группировкой и агрегатами.
Разумеется. Вы же хотели конкретный пример — вы его получили. А теперь жалуетесь, что он имеет мало чего общего с вашими задачами.
Вот еще. Я точно знаю, что есть СУБД, которые быстрее тех СУБД, которыми я пользуюсь. Заодно я знаю, благодаря чему это происходит, и что я теряю, чтобы приобрести эту скорость.
Ну раз вы всё знаете наперёд без тестирования, то мне нечего вам возразить :-)lair
18.09.2015 16:43Плюс-минус террабайт в таких масштабах погоды не делают.
Вообще-то, они денег стоят. Денег и времени.
Ну раз вы всё знаете наперёд без тестирования, то мне нечего вам возразить
Я как раз знаю на основании тестирования, по большей части.
kefirfromperm
21.09.2015 08:2225% в кровавом энторпрайсе — это, порой десятки терабайт, а то и сотни. Это, во-первых, SAN. Это резервирование в территориально-распределенных ДЦ. Это бэкапы. Это, в конце-концов, новые стойки в ДЦ. Но самое главное, это всё надо согласовать. На согласование +25% SAN уйдет больше ресурсов организации, чем на преимущества от внедрения модной СУБД.
vintage
21.09.2015 12:18-2Вы так говорите будто объёмы данных не растут просто по естественным причинам чуть ли не удваиваясь каждый год.
zuborg
21.09.2015 13:45+1Речь идет о сопоставимости, а не совпадении.
25% это всегда 25%, независимо от того составляют они десятки терабайт или сотни петабайт.
bigfatbrowncat
18.09.2015 16:47+1А что? Для вас 25% — это несопоставимы? Это же не в 3 раза, правда? Ведь самый ценный ресурс в Enterprise это время разработчиков и время простоя системы из-за багов, так? А купить лишних винчестеров они не пожалеют денег…
тестируете вы на конкретной задаче, которая для графов выгодна
Так автор, как мне показалось, как раз стремится доказать, что таких «выгодных» — большинство.lair
18.09.2015 16:49Для вас 25% — это несопоставимы?
Для меня 25% могут иметь существенное значение при оценке.
Так автор, как мне показалось, как раз стремится доказать, что таких «выгодных» — большинство.
К сожалению, я не вижу даже попытки такого доказательства.
Coffin
18.09.2015 13:12+2Для разных зада, свои БД :)
GrizliK1988
18.09.2015 15:03Да для них БД не нужны, мне кажется :)
Coffin
18.09.2015 15:09Да я всё жду, когда же будет клавиатура, которая будет из мозга печатать, а то мои пальцы намного медленнее мыслей :(
fogone
18.09.2015 14:31+4Ваш атниконформизм заключается в том, что вы назло всем неправильно пишете слово нонконформизм?
vintage
18.09.2015 14:38А вы сами-то читали статью, на которую ссылаетесь? :-)
Нонконформи?зм — стремление индивида придерживаться и отстаивать установки, мнения, результаты восприятия, поведение и так далее, прямо противоречащие тем, которые господствуют в данном обществе или группе. Часто считается синонимом понятия «негативизм» и антонимом понятия «конформизм». В некоторых случаях нонконформизмом называют просто готовность индивида отстаивать свою личную позицию в тех случаях, когда она противоречит позиции большинства. В таких случаях описанное в данной статье явление выделяют под названием «антиконформи?зм»
fogone
18.09.2015 15:03+2Вы сами-то читали, что запостили?
готовность индивида отстаивать свою личную позицию в тех случаях, когда она противоречит позиции большинства
и
человек, который не держится за свои привычки и всегда готов их поменять, если в том есть необходимость
совсем не одно и тоже. Ваше опредление больше похоже на лабильностьvintage
18.09.2015 16:02+1В данном контексте это родственные понятия. Если вам так станет легче — можете считать, что уделали меня в этом терминологическом споре :-)
На «лабильность психики» уж точно не похоже.
ragimovich
18.09.2015 14:54+3http://orientdbleaks.blogspot.com/2015/06/the-orientdb-issues-that-made-us-give-up.html
Хорошую базу вы для продакшена выбрали. Главное, что не пришлось над дизайном и запросами к РСУБД думать.vintage
18.09.2015 15:59-1Скандалы, интриги, расследования… как-то много уж в той статье притянутых за уши пунктов. То форкнули проект на ГитХабе, не спросив разрешения, то удалили тег «bug» с не актуальных репортов. На тему стабильности — сам я не сталкивался с такими проблемами за тот же год, но я и не обновлял СУБД каждый месяц на последнюю версию. Тем не менее те репорты, что я создавал — довольно быстро фиксились. Я бы тоже предпочёл, чтобы багов не было вообще и всё сразу было идеально :-)
Но альтернатив у OrientDB я особо не вижу. Возвращаться на реляционные — боже упаси. И не потому, что я не люблю думать о дизайне и запросах, а именно потому, что я люблю думать о дизайне. А дизайн реляционной базы — это всегда костыль на костыле и приходится решать проблемы, которых вообще быть не должно при правильном дизайне.lair
18.09.2015 16:40+1А дизайн реляционной базы — это всегда костыль на костыле
Серьезно? Всегда?vintage
18.09.2015 18:14-1А разве есть контр-пример не уровня «привет мир»?
lair
18.09.2015 18:14+1Конечно. Многие классические учетные задачи.
vintage
18.09.2015 18:26-1Приведите пример хотя бы одной, что ли.
lair
18.09.2015 18:30Да легко.
Вот организация учитывает находящиеся в ее собственности запасы нефти, газа и разных ценных металлов. Ее интересует — на каждый отчетный момент — общая стоимость запасов, а так же стоимость в разбивке по конкретному наименованию, виду, учетной категории и складу. И все то же самое — по объему и весу.
Как мы понимаем, для РСУБД это очень простая по дизайну задача. И я что-то не вижу там ни одного, как вы выражаетесь, костыля.vintage
18.09.2015 19:01Костыли начнутся, когда надо будет строить отчёты по параметрам, а параметры у всех типов ресурсов разные. Придётся либо каждый ресурс в отдельной таблице хранить, либо выносить параметры в отдельную таблицу и приджойнивать её. Это ещё одна фундаментальная проблема РСУБД, которую я забыл упомянуть.
lair
18.09.2015 19:04Вот если такая ситуация случится, то можно будет смотреть, насколько костыльно такое решение. Я-то не вижу фундаментальной проблемы ни в одном, ни в другом, ни в третьем известном мне решении.
vintage
18.09.2015 19:09-4Ну ок, вот мы и нашли область применения реляционный СУБД. Довольно узкая область, надо сказать :-)
lair
18.09.2015 21:05Угу, очень узкая — львиная доля всех количественных отчетов, включая чуть менее, чем все финансы.
vintage
18.09.2015 21:43В довольно редком приложении есть только отчёты :-)
lair
18.09.2015 21:47Но отчеты очень удобно строить по реляционной БД (или по OLAP, который тоже работает по реляционной БД). А дальше либо оказывается, что вносить в нее данные тоже удобно, либо, если неудобно, на внесение данных берется другое хранилище.
vintage
18.09.2015 22:03Да также как и по графовой, в принципе. Индексы — не прерогатива реляционных баз.
lair
18.09.2015 22:08Напомню, что изначально вы утверждали, что дизайн реляционной БД — всегда костыль на костыле. А сейчас мы дошли до того, что «ну и на графовой так сделать можно».
vintage
18.09.2015 22:27-2Кроме той маленькой области, да, костыль на костыле.
1. многие-ко-многим — костыли
2. деревья — костыли
3. большое разнообразие свойств — костыли
Без всего этого, ниша сужается до области OLAP, где опять же рулят не реляционные СУБД.lair
18.09.2015 22:47маленькой
Маленькой, серьезно?
многие-ко-многим — костыли
А почему вы считаете промежуточную таблицу костылем, кстати? Это всего лишь стандартный шаблон, вполне логично описывающий происходящее.
деревья — костыли
«Костыли» нужны, когда вы хотите иметь эффективные выборки по определенными видам деревьев. Это нужно не всегда. И, в общем-то, некоторые СУБД уже включают встроенную поддержку деревьев, так что тут тоже костыли пропали.
большое разнообразие свойств — костыли
Нет там никаких костылей.
ниша сужается до области OLAP, где опять же рулят не реляционные СУБД.
… а какие?vintage
18.09.2015 23:05-1А почему вы считаете промежуточную таблицу костылем, кстати? Это всего лишь стандартный шаблон, вполне логично описывающий происходящее.
Лишняя сущность, усложняющая работу, замедляющая выборки.
«Костыли» нужны, когда вы хотите иметь эффективные выборки по определенными видам деревьев.
Было бы странно хотеть неэффективные выборки)
И, в общем-то, некоторые СУБД уже включают встроенную поддержку деревьев, так что тут тоже костыли пропали.
Наличие встроенной поддержки костылей не делает их более эффективными. рекурсивные запросы не избавляют от сложности log(N) каждого хопа, где N — число записей в таблице. ordpath не избавляет от обновления кучи узлов при изменении дерева.
Нет там никаких костылей.
Да ну? И как же без костылей засунуть в РСУБД гетерогенные сущности?
… а какие?
Тут я не специалист, но говорят колоночные рулят в этой области.lair
18.09.2015 23:07+1Лишняя сущность, усложняющая работу, замедляющая выборки.
У вас есть реальные тесты, подтверждающие замедление?
Было бы странно хотеть неэффективные выборки)
Иногда конкретный вид выборок никого не волнует (его просто нет в бизнес-кейсе).
Наличие встроенной поддержки костылей не делает их более эффективными. рекурсивные запросы не избавляют от сложности log(N) каждого хопа, где N — число записей в таблице. ordpath не избавляет от обновления кучи узлов при изменении дерева.
Понимаете ли, если для меня работа с деревом прозрачна, и скорость меня устраивает — чего еще мне хотеть?
Да ну? И как же без костылей засунуть в РСУБД гетерогенные сущности?
А в чем проблема?vintage
19.09.2015 11:07-2У вас есть реальные тесты, подтверждающие замедление?
Временная сложность алгоритмов для вас не достаточный аргумент? У каждого джойна она О(n*log(N)) при использовании индекса.
Иногда конкретный вид выборок никого не волнует (его просто нет в бизнес-кейсе).
Мы опять скатились к ограничению области применимости РСУБД: «когда плевать на эффективность выборки» или «только для небольших иерархий».
А в чем проблема?
В том, что в одной таблице могут быть лишь гомогенные сущности.lair
19.09.2015 11:19Временная сложность алгоритмов для вас не достаточный аргумент?
Нет. Когда мы начинаем говорить о конечной производительности, константы тоже имеют значение.
У каждого джойна она О(n*log(N)) при использовании индекса.
Только если стоимость прохода по индексу — O(log(N))
Мы опять скатились к ограничению области применимости РСУБД: «когда плевать на эффективность выборки»
Извините, но… нет. Сами по себе РСУБД дают очень эффективный механизм выборок.
В том, что в одной таблице могут быть лишь гомогенные сущности.
А внутри одного класса в ООП могут быть только объекты этого класса. И что?vintage
19.09.2015 11:37Нет. Когда мы начинаем говорить о конечной производительности, константы тоже имеют значение.
Есть основания полагать, что константы при прямых ссылках больше?
Только если стоимость прохода по индексу — O(log(N))
А есть индексы с меньшей сложностью?
Извините, но… нет. Сами по себе РСУБД дают очень эффективный механизм выборок.
Не более эффективный, чем в любой другой СУБД с поддержкой индексов. Алгоритмы одни и те же.
А внутри одного класса в ООП могут быть только объекты этого класса. И что?
То, что в ООП есть полиморфизм. А в РСУБД всё гвоздями приколочено к таблицам. И один индекс на несколько таблиц не построить, и выборка из 100 таблиц требует полного перечисления их имён и связей между ними.lair
19.09.2015 11:58Есть основания полагать, что константы при прямых ссылках больше?
Есть основания полагать, что мы ничего о них не знаем. Равно как и о цене поддержки.
А есть индексы с меньшей сложностью?
Orient же утверждает, что сделал доступ O(1) к произвольному элементу БД. Значит, ничего не мешает сделать так же организованный доступ и в РСУБД.
Не более эффективный, чем в любой другой СУБД с поддержкой индексов. Алгоритмы одни и те же.
Это утверждение работает в любую сторону.
То, что в ООП есть полиморфизм.
… создающий кучу реализационных проблем регулярно.
И один индекс на несколько таблиц не построить
Построить. Но зачем?
и выборка из 100 таблиц требует полного перечисления их имён и связей между ними.
Плата за структуру.vintage
19.09.2015 12:06-1Orient же утверждает, что сделал доступ O(1) к произвольному элементу БД. Значит, ничего не мешает сделать так же организованный доступ и в РСУБД.
Архитектура мешает. Нужно не просто id в поле хранить, но и поддерживать такие значения как linkmap, linkset, linklist.
… создающий кучу реализационных проблем регулярно.
Каких же?
Построить. Но зачем?
Как? И что значит зачем? Чтобы делать выборку по одному индексу, а не по 100.
Плата за структуру.
Полиморфизм позволяет не платить за структуру.lair
19.09.2015 12:22+1Нужно не просто id в поле хранить, но и поддерживать такие значения как linkmap, linkset, linklist.
Зачем? Если мы можем сделать O(1) доступ по ключу, то дальше стоимость выборки коллекции — O(n) даже в случае реализации с дополнительной таблицей.
Каких же?
Необходимость придерживаться LSP, например. Про проблему квадрата и прямоугольника слышали?
Полиморфизм позволяет не платить за структуру.
Спорный тезис. Насколько я помню, сама по себе поддержка наследования в языке приводит к (некоторым) потерям производительности.vintage
19.09.2015 13:24-1O(1) по ключу мы можем добиться лишь потратив O(N) памяти.
К полиморфизму проблемы наследования относятся очень опосредованно.
Во первых мы про СУБД, а не про ЯП говорим. А во вторых, не все языки одинаково бесполезны.lair
19.09.2015 13:29+1O(1) по ключу мы можем добиться лишь потратив O(N) памяти.
Передайте это ориенту, ага?
Во первых мы про СУБД, а не про ЯП говорим. А во вторых, не все языки одинаково бесполезны.
Я, если честно, не знаю, что вы понимаете под полиморфизмом в СУБД.vintage
21.09.2015 01:23Передал, говорит у него там O(n) по памяти, где n — число связей с заданным именем в заданном узле. И эта сложность не зависит от общего числа узлов в графе. В отличие от индексов.
Полиморфизм примерно в этом:
create class Cart create class Product create class Database extends Product create class Framework extends Product create property Cart linklist Product create property Product.name string create property Product.price decimal create property Database.acid boolean create property Framework.language string create index Product.price notunique insert into Database content { "name" : "OrientDB" , "acid" : true , price : 0 } insert into Framework content { "name" : "NodeJS" , "language" : "javascript" , price : 0 } select from Product where price < 1000
lair
21.09.2015 01:41Передал, говорит у него там O(n) по памяти, где n — число связей с заданным именем в заданном узле. И эта сложность не зависит от общего числа узлов в графе. В отличие от индексов.
Индексы здесь вообще ни при чем — они для данной задачи не нужны, весь доступ осуществляется по основному ключу (я под индексом понимаю вторичный индекс). Так что я не очень понимаю, почему, если считать, что O(1) по ключу — достижимы, то нельзя сделать выборку коллекции за O(n), не используя никаких дополнительных типов.
Полиморфизм примерно в этом:
Вы правда не знаете, как это реализуется в реляционных СУБД? Я знаю три традиционных способа, дающих разные преимущества (и больше одного ОРМ, который сделает это незаметно для меня).
Вообще, конечно, выглядит красиво, ничего не скажешь. Но вопрос производительности остается неочевидным.vintage
21.09.2015 01:48-2Первичный индекс ни чем не лучше вторичного, кроме того, что его не нужно явно объявлять.
Я даже 4 способа знаю разной степени костыльности :-)lair
21.09.2015 01:52Ну во-первых, первичный индекс лучше тем, что одна операция доступа вместо двух, а в случае ключа — еще и уникальность гарантирована.
А во-вторых, повторю вопрос: если предположить, что используется доступ по ключу с константной стоимостью (т.е. то, что утверждается в ориенте), что мешает организовать проход по коллекции за линейное время (от объема коллекции)?vintage
21.09.2015 02:05В Ориенте доступ по ключу не за константное время, а за тот же логарифм. Другое дело, что ссылки — это не ключи, а физические координаты. РСУБД же нужно используя первичный индекс транслировать логический адрес (идентификатор) в физический (имя файла + смещение).
lair
21.09.2015 11:16Фундаментальной разницы между ключом и физическими координатами — нет, можно использовать физические координаты в качестве ключа. Правда, тут РСУБД (если мы хотим сохранить семантику) все-таки понадобится индекс…
И вот пока я думал эту мысль, до меня внезапно дошла простая вещь, которую я почему-то пропустил раньше. Помните вот этот диалог?
Только если стоимость прохода по индексу — O(log(N))
А есть индексы с меньшей сложностью?
Так вот, индексы с меньшей сложностью есть. У хэш-таблицы амортизированная сложность доступа — O(1).vintage
21.09.2015 12:41Чтобы хеш таблица работала за O(1) необходим непрерывный участок памяти объёмом O(N). И это без хеширования. С хешированием у нас появляется вероятность коллизии и тогда объём памяти нужно кратно увеличить, чтобы коллизии происходили не слишком часто. Кроме того, хеш таблицы очень дорого перестраивать для поддержки больших объёмов данных.
lair
21.09.2015 13:20Чтобы хеш таблица работала за O(1) необходим непрерывный участок памяти объёмом O(N).
Не обязательно памяти. Любого хранилища.
Кроме того, хеш таблицы очень дорого перестраивать для поддержки больших объёмов данных.
А вот это вопрос констант как раз, который вы раньше проигнорировали.vintage
22.09.2015 00:58Я говорил не только про оперативную память.
Не игнорировал. И тут дело не в константах, а именно в алгоритмической сложности ресайза. Бинарные деревья куда лучше приспособлены для больших объёмов.lair
22.09.2015 01:01Я говорил не только про оперативную память.
Осталось выяснить, каким же же чудом Ориент обходит эти ограничения.
И тут дело не в константах, а именно в алгоритмической сложности ресайза.
Еще раз: амортизированная алгоритмическая сложность хэш-таблицы — O(1), как на чтение, так и на добавление. Ресайз сюда включен.vintage
22.09.2015 01:52Никак не обходит.
Ну да, обычно всё летает, а иногда встаёт колом на час.lair
22.09.2015 11:23Никак не обходит.
Прекрасно, значит, и здесь у него (ориента) нет никаких концептуальных преимуществ.
Ну да, обычно всё летает, а иногда встаёт колом на час.
Scheduled maintenance рулит. Иначе вы на банальном приросте файла под БД можете очень больно лечь.vintage
23.09.2015 23:52Прекрасно, значит, и здесь у него (ориента) нет никаких концептуальных преимуществ.
Есть. И я не буду больше повторять про ссылки.
Scheduled maintenance рулит. Иначе вы на банальном приросте файла под БД можете очень больно лечь.
По вашему увеличение файла происходит путём копирования содержимого из маленькой непрерывной области в большую? :-)lair
24.09.2015 01:00По вашему увеличение файла происходит путём копирования содержимого из маленькой непрерывной области в большую?
Нет, а с чего вы это взяли?
VolCh
19.09.2015 13:27Но отчеты очень удобно строить по реляционной БД
Не очень удобно. Даже если забыть про избыточность собственно SQL-запроса (разработчик вынужден хранить в голове связи типа contract.id = contract_transaction.contract_id и указывать их в запросе явно, хотя до этого указывал СУБД, что contract_transaction.contract_id не может указывать может указывать только на contract.id, не забывать включать таблицу в FROM, если указал её в SELECT или WHERE), то многие часто встречающиеся для отчётов задачи решаются средствами SQL нетривиально. Например, отчёт по балансу какого-то числового агрегатного поля сущности по дням, где должен быть указан баланс на начало дня, начисления за день, списания за день, баланс на конец дня, причём баланс на начало дня должен быть ноль, даже если сущность ещё не существует, отчёт должен быть по каждой дате, даже если транзакций по сущности не было, а если транзакций не было, то начисления и списания тоже должны быть нулями. А в наличии у нас сущность и
транзакции по ней. Как минимум, придётся извращаться с преобразованием NULL в 0 и установлением начального баланса в 0.lair
19.09.2015 13:31Как минимум, придётся извращаться с преобразованием NULL в 0
Вот поэтому изначально в реляционной теории NULL и не было. Соответственно, как только вы решаете проблему с преобразованием «нет данных» в нули (а это чистое бизнес-требование), ваша задачка решается легко и просто.
Впрочем, я с удовольствием послушаю про СУБД, в которой это строить проще.VolCh
20.09.2015 16:14Бог с ним с преобразованием реальных данных, в конце концов на уровне интерфейса можно указать, что NULL отображать как 0, '', 'нет данных' или ещё как (может даже удобнее для бизнеса чем 0). Но вот start_balance + SUM(tr.amount) (где tr.amount NULL как отсутствующая в результате LEFT JOIN) или любые подобные агрегатные данные вернут тоже NULL, который так просто на уровне интерфейса не разрешить.
А я не говорил, что они есть я спорил с утверждением, что в SQL строить подобные отчёты, довольно обычные в практике, удобно. Имхо, реляционная модель вообще (а её реализация в SQL особенно) слабо приспособлена для реализации, с одной стороны, отношений типа «имеет», «содержит», «принадлежит» и т. п. между сущностями и, с другой, для агрегирующих выборок с известным начальным состоянием.
Проще это делается в, например, документо-ориентированных СУБД, в которых в качестве языка запросов используется, например, javascript — обычный reduce на коллекцию с начальным состоянием. Другое дело, что цена этой простоты меня лично не устроила и мучаюсь с Postgre- и, пока, MySql. Ещё активно навязывают (поставщики внешних решений MS SQL через начальство), но пока сопротивляюсь.lair
20.09.2015 22:07Но вот start_balance + SUM(tr.amount) (где tr.amount NULL как отсутствующая в результате LEFT JOIN)
Просто нужно вытаскивать все агрегаты отдельно, тогда можно будет разделять «транзакций за день не было» и «общий баланс транзакций за день — 0». И складывать на уровне интерфейса, благо, это просто.
(на уровне SQL тоже не сложно, прямо скажем).
Проще это делается в, например, документо-ориентированных СУБД, в которых в качестве языка запросов используется, например, javascript — обычный reduce на коллекцию с начальным состоянием.
Описываемая вами простота приходит не от документо-ориентированности — а от использования JS. Сама модель никак на это не влияет.VolCh
22.09.2015 15:15В этой ветке я ничего не говорил про реляционную модель, а говорил про удобство самого языка запросов. Часть неудобств проистекает из недостатков реляционной модели (многие из них с той или иной мерой успешности решаются разными производителями, как правило, по разному), а часть самим языком запросов, который создавался чтобы «любая домохозяка могла сделать запрос по базе».
inborn_killer
18.09.2015 14:59+5JSON убили, пора приниматься за РСУБД. Неизменно деструктивные настроения у автора =)
zodchiy
18.09.2015 15:06+11Для быстрого и комфортного перемещения были созданы автомашины.
Я люблю лес.
По лесу машины передвигаются плохо, а велосипеды хорошо.
Вывод: Считаю надо выкинуть все автомашины и всем пересесть на велосипеды.vintage
24.09.2015 00:10Для быстрого перемещения были созданы суперкары.
Для комфортного — лимузины.
Но для повседневной жизни обычно выбирают хетчбэк.
lair
18.09.2015 15:53+6Многие SQL-профи тут обычно заявляют, мол деревья и тем более графы в предметных областях почти не встречаются. Но стоит немного выйти из зоны комфорта как тут же увидишь, что любая предметная область на самом деле представляет из себя граф — набор сущностей, между которыми есть разнообразные отношения.
Это утверждение неверно. Любую предметную область можно представить в виде графа, однако это не означает, что это представление для нее наиболее эффективно. И тем более не значит, что это представление нужно выбирать для реализации.
Собственно, все же уже сказано в хорошей книжке.vintage
18.09.2015 19:30-3Но также любую предметную область можно представить в виде таблиц, однако это не означает, что это представление для нее наиболее эффективно. И тем более не значит, что это представление нужно выбирать для реализации. Однако большинство предметных областей на граф ложатся лучше, чем на таблицы.
lair
18.09.2015 21:14+3Однако большинство предметных областей на граф ложатся лучше, чем на таблицы.
Что вы понимаете под «лучше»? Ну и в любом случае мне, конечно, интересно увидеть статистику, на основании которой вы делаете это утверждение.
(отдельно, конечно, неплохо бы определиться, что же вы именно понимаете под графами...)vintage
18.09.2015 22:09-3В статье я и изложил свои мысли на этот счёт.
lair
18.09.2015 22:10Никакой статистики — равно как и адекватного определения того, что такое «граф», на который предметные области ложатся лучше — в вашей статье нет.
vintage
18.09.2015 22:39-1Вы не знаете, что такое граф?
Бизнес модель — коллекция сущностей с отношениями.
Графовая модель — коллекция узлов со связями.
Реляционная модель — таблицы с данными и всё.
Первая на вторую мапится 1-в-1. На третюю не памятся, ибо нет отношений (они указываются только потом, в запросе), да и сущности по сложнее кортежа примитивов.lair
18.09.2015 22:56+1Я знаю, что такое граф. Вопрос в том, например, могут ли узлы графа иметь свои свойства? Типы? (я говорю именно о графе как концепции, а не реализации в ориенте)
Реляционная модель — таблицы с данными и всё.
На самом деле, нет. Реляционная модель — это таблицы с данными и их связи.
Первая на вторую мапится 1-в-1.
А еще бизнес-модель точно так же «точно» маппится на документо-ориентированную парадигму (потому что там тоже коллекция сущностей со связями) и на объектно-ориентированную парадигму.
Это все еще не значит, что любое из перечисленных представлений (включая реляционное) по каким-то причинам лучше подходит для реализации всех задач.vintage
18.09.2015 23:31Вполне могут, почему нет?
В таблицах нету связей. Там есть одинаковые числа в разных колонках разных таблиц. Смысл связей они обретают лишь при запросе и соответствующие записи могут быть найдены лишь по индексам.
Документная модель со связями — это уже графовая модель. Типа той, что мы видим в Ориенте.
lair
18.09.2015 23:32+1В таблицах нету связей.
Это экзистенциальный вопрос. В таблице есть информация, позволяющая однозначно определить связанный объект. Этого достаточно.
Документная модель со связями — это уже графовая модель.
Тогда и табличная модель со связями — графовая модель, после чего вообще сравнивать нечего становится.vintage
19.09.2015 10:54Разумеется логически связи есть (иначе приложение бы никакое было не построить), но физически нет ссылок на другие записи. Есть только числа по которым можно найти связанную запись только через поисковой индекс. В этом смысле числа ни чем не лучше любого другого типа данных. Вы можете к возрасту приджойнить айдишники и получить странный результат. А РСУБД ничего на это даже не возразит. Так что притянуть отношения к таблицам можно, но выражены они не явно и требуют специального шаманства.
lair
19.09.2015 11:15но физически нет ссылок на другие записи. Есть только числа по которым можно найти связанную запись только через поисковой индекс.
Вы так говорите, будто в других БД «физически» хранятся не «числа» (опустим для простоты тот факт, что идентификатором записи может быть что угодно). Те же самые числа, пусть даже в OrientDB они являются указателями на конкретное физическое место в БД.
Семантику этих «чисел» обеспечивают метаданные, лежащие поверх, и ограничивающие операции. Сейчас, наверное, все РСУБД поддерживают внешние ключи, как для ограничения множества допустимых значений, так и для распространения изменений. Семантически это эквивалентно ссылкам на объекты.
Вы можете к возрасту приджойнить айдишники и получить странный результат. А РСУБД ничего на это даже не возразит.
Да, могу — ни одна известная мне РСУБД не имеет ограничений на объекты под джойнами. Но есть и оборотная сторона — я могу приджойнить возраст к возрасту, или имя к имени, или результат группировки к результату группировки. Можно ли так сделать в графовой БД?
vintage
19.09.2015 11:53Не совсем эквивалентны, но ладно. С той лишь оговоркой, что реализуются эти ссылки крайне не эффективно — через прослойку из индексов.
Можно, через подзапросы.lair
19.09.2015 12:00Можно, через подзапросы.
Во-первых, являются ли «подзапросы» свойством любой графовой БД?
Во-вторых, какова их функциональность и эффективность по сравнению с РСУБД?vintage
19.09.2015 12:111. Я не говорю про любую ГСУБД. Но в любой толковой — можно. Из толковых я знаю только одну.
2. Да такая же при наличии индексов. Разве что для full outer join нужно шаманить.lair
19.09.2015 12:25+1Я не говорю про любую ГСУБД. Но в любой толковой — можно. Из толковых я знаю только одну.
Значит, это не врожденное свойство графовых БД.
Да такая же при наличии индексов. Разве что для full outer join нужно шаманить.
Правда?
У меня есть две таблицы (два класса в терминах ориента), «книги» и «фильмы». В каждой из них есть поле «год». Мне нужно получить таблицу вида «год выхода — число книг — число фильмов». Считаем, что с каждой стороны есть хотя бы по одной записи для каждого года, поэтому достаточноINNER JOIN
.vintage
21.09.2015 02:39Разумеется, не все ГСУБД одинаково полезны :-)
Если честно, лень шаманить с селектами… в ГСУБД эта задача решается несколько иначе и более эффективно:
select value , book.length() as booksCount , movies.lengh() as moviesCount from Year
При этом это ограничение «с каждой стороны есть хотя бы по одной записи для каждого года» не требуется.
lair
21.09.2015 11:24+1Во-первых, это не «более эффективно» — теперь каждый раз, когда мне нужна информация о годе для книги или кино, я должен пройти по связи.
Во-вторых, увеличивается стоимость поддержки — когда у меня появляется новая сущность (диск, например), в котором я сделаю связь с годом, ориент сам добавит «ответное» свойство со стороны года, или его будет нужно добавлять руками?
В-третьих, это как раз типичный костыль: графовая модель не справляется с задачей, которая для реляционной модели проста, и вы вынуждены изменять семантику модели так, чтобы она влезла в граф.
В конце концов это приведет к тому, что у вас все свойства будут ребрами (со всеми вытекающими отсюда проблемами), вы получите «чистый» граф и модель категорий по Партриджу (которую на хабре уже обсуждали).vintage
21.09.2015 13:011. Это в РСУБД переход по связи дорогой. Тут же это почти ничего не стоит (прочитать лишний блок памяти, который, к тому же, скорее всего возьмётся из кэша).
2. Если используется графовое апи, то обратные связи создаются автоматически. Если же документное (которое я нахожу более практичным), то ответное нужно создавать руками.
3. Я бы не назвал это таким уж прям костылём. Если у нас выводится аналитика по годам, то без сущности «год выпуска» так или иначе не обойтись. К ней надо будет привязывать не только вышедшие произведения, но и ежегодные премии, аналитические статьи и тп. А не вытягивать их по косвенным данным (датам во всех этих сущностях) при каждом запросе, внимательно следя, чтобы диапазоны не пересекались. Тем более что премия за текущий год может вручаться в следующем. А аналитическая статья за любой год может выйти хоть через десятилетие.
4. Можно ссылку, где обсуждали?lair
21.09.2015 13:31Это в РСУБД переход по связи дорогой. Тут же это почти ничего не стоит (прочитать лишний блок памяти, который, к тому же, скорее всего возьмётся из кэша).
Это все равно дополнительная операция. А кэши — они во всех СУБД есть.
Если же документное (которое я нахожу более практичным), то ответное нужно создавать руками.
Вот и увеличение стоимости поддержки.
Если у нас выводится аналитика по годам, то без сущности «год выпуска» так или иначе не обойтись.
Год выпуска — это не сущность, а атрибут.
К ней надо будет привязывать не только вышедшие произведения, но и ежегодные премии, аналитические статьи и тп. А не вытягивать их по косвенным данным (датам во всех этих сущностях) при каждом запросе, внимательно следя, чтобы диапазоны не пересекались. Тем более что премия за текущий год может вручаться в следующем. А аналитическая статья за любой год может выйти хоть через десятилетие.
Все эти проблемы решаются введением соответствующего атрибута, сущность все еще не нужна.
Можно ссылку, где обсуждали?
habrahabr.ru/post/246313
habrahabr.ru/post/245241
И вообще в комментариях почти к любому поcту maxstroyvintage
21.09.2015 13:41Это все равно дополнительная операция.
Она как минимум лучше масштабируется, чем джойны таблиц.
Вот и увеличение стоимости поддержки.
Один раз пишется обобщённый код и всё. Ну то есть я реализовал своё графовое апи с поддержкой как двусторонних так и односторонних связей. То, что есть в Ориенте — всегда двустороннее и направленное
Год выпуска — это не сущность, а атрибут.
Ссылка на сущность хранится в атрибуте. Это философский спор :-) Я лично усматриваю в годе выпуска все признаки сущности. Сформулировать их пока не возьмусь, чисто интуитивно.
Все эти проблемы решаются введением соответствующего атрибута, сущность все еще не нужна.
Но с ней в целом удобней.
habrahabr.ru/post/246313
Спасибо, почитаю.
habrahabr.ru/post/245241lair
21.09.2015 13:44Она как минимум лучше масштабируется, чем джойны таблиц.
Почему?
Один раз пишется обобщённый код и всё.
А создает описание связей в БД тоже «обобщенный код»?
Я лично усматриваю в годе выпуска все признаки сущности.
Попробуйте сформулировать, и поймете, что по этим признакам всё — сущность. Это, конечно, нативный для графа подход (все есть вершина кроме того, что ребро), но вы уверены, что вам будет удобно так работать.
Но с ней в целом удобней.
Удобнее вам реализовывать на графовой БД. Но в бизнесе этого нет… и что вы там говорили про то, что предметная область лучше ложится на граф?vintage
21.09.2015 13:57Почему?
Потому что скорость перехода по ссылке не зависит от числа записей в таблице…
А создает описание связей в БД тоже «обобщенный код»?
Вполне, почему бы и нет?
вы уверены, что вам будет удобно так работать.
Да, весьма.
Удобнее вам реализовывать на графовой БД. Но в бизнесе этого нет… и что вы там говорили про то, что предметная область лучше ложится на граф?
В бизнесе есть «отчётные периоды» и это вполне себе бизнес сущности. И с ней удобнее и быстрее работать как с отдельной сущностью, а не жонглировать временными метками.lair
21.09.2015 13:59Потому что скорость перехода по ссылке не зависит от числа записей в таблице…
Уже проходили: для реляционной БД это тоже возможно.
Вполне, почему бы и нет?
Ну так, представляю себе результаты его работы.
Да, весьма.
Пробовали? Пока все ваши примеры — они документо-ориентированы.
В бизнесе есть «отчётные периоды» и это вполне себе бизнес сущности.
Не надо путать отчетные периоды и год выхода. Это очень разные вещи. А временные метки вы себе вообще сам придумали, я про них не слова не сказал.vintage
22.09.2015 01:08Уже проходили: для реляционной БД это тоже возможно.
Если б всё было так легко, никто бы не пилил NoSQL решения.
Ну так, представляю себе результаты его работы.
Озвучите?
Пробовали? Пока все ваши примеры — они документо-ориентированы.
Бизнес вообще документно ориентирован.
Не надо путать отчетные периоды и год выхода.
Вы строите отчёты по годам. Вполне себе отчётные периоды.lair
22.09.2015 01:11+1Если б всё было так легко, никто бы не пилил NoSQL решения.
А вы думаете, NoSQL решения «пилят» из-за невозможности сделать константное время доступа по ключу?
Озвучите?
Если вкратце, то:book.Editor_Person
.
Бизнес вообще документно ориентирован.
Ну и как же вы собираетесь его положить на чистый граф тогда?
Вы строите отчёты по годам. Вполне себе отчётные периоды.
Нет, я строю отчеты по атрибуту «год выхода». Это не то же самое, что «отчетный период — 2010 год» или «финансовый год 2010».vintage
22.09.2015 02:00-4А вы думаете, NoSQL решения «пилят» из-за невозможности сделать константное время доступа по ключу?
Из-за фундаментальных проблем масштабирования РСУБД.
Если вкратце, то: book.Editor_Person.
Что это?
Ну и как же вы собираетесь его положить на чистый граф тогда?
Бизнес документы тоже имеют перекрёстные ссылки.
Нет, я строю отчеты по атрибуту «год выхода». Это не то же самое, что «отчетный период — 2010 год» или «финансовый год 2010».
Не вижу разницы.norguhtar
22.09.2015 07:13+1Из-за фундаментальных проблем масштабирования РСУБД.
Как интересно! А расскажите какие там есть проблемы? И да кстати посмотрите про то как PostgreSQL ускоряют при помощи GPGPU.
vintage
22.09.2015 10:39Спасибо за ссылку. Но GPU ускорение работает только если все данные помещаются в память видеокарты и при наличии этой самой видеокарты. При этом алгоритмическая сложность никуда не девается, а просто уменьшается константа.
lair
22.09.2015 11:26Что это?
Это типичный пример именования, вышедшего из под обобщенного кода.
Бизнес документы тоже имеют перекрёстные ссылки.
Перекрестные ссылки — это, конечно, граф, но бизнес-документы — это не чистый граф, а речь выше шла именно об этом.
Не вижу разницы.
Я, в принципе, уже заметил.
Окей, представьте, что у вас не год, а дата — и вам надо строить аналитику по датам (рождения, смерти, свадьбы и развода).vintage
22.09.2015 12:06-1Это типичный пример именования, вышедшего из под обобщенного кода.
Зачем тип указывать в имени свойства?
Перекрестные ссылки — это, конечно, граф, но бизнес-документы — это не чистый граф, а речь выше шла именно об этом.
Что такое «грязный граф»?
Окей, представьте, что у вас не год, а дата — и вам надо строить аналитику по датам (рождения, смерти, свадьбы и развода).
Точно так же, создаём отдельные узлы для дат и имеем быструю аналитику по ним. Говорю же, принципы работы с графами несколько отличаются от подходов к которым вы привыкли при работе с таблицами.lair
22.09.2015 13:12Зачем тип указывать в имени свойства?
Потому что обобщенный код так сгенерил.
Что такое «грязный граф»?
Граф, в котором у вершин есть свойства.
Точно так же, создаём отдельные узлы для дат и имеем быструю аналитику по ним.
Вы себе представляете количество таких вершин?
Говорю же, принципы работы с графами несколько отличаются от подходов к которым вы привыкли при работе с таблицами.
Спасибо, я в курсе. Только почему-то подходы, применяемые в реляционной модели, вы считаете костылями, а подходы, применяемые в графовой — нет.vintage
22.09.2015 14:09Потому что обобщенный код так сгенерил.
Напишите нормальный обобщённый код :-)
Граф, в котором у вершин есть свойства.
Теория графов не накладывает никаких ограничений на вершины.
Вы себе представляете количество таких вершин?
Не больше чем узлов в индексе.
Спасибо, я в курсе. Только почему-то подходы, применяемые в реляционной модели, вы считаете костылями, а подходы, применяемые в графовой — нет.
Потому что они имеют большую алгоритмическую сложность и меньшую наглядность.lair
22.09.2015 14:12Напишите нормальный обобщённый код
Если бы можно было написать нормальный обобщенный код, порождающий модель, соответствующую домену, программистов можно было бы выкинуть на свалку.
Теория графов не накладывает никаких ограничений на вершины.
И как следствие никак не описывает алгоритмы для работы с «дополнительными» данными.
Не больше чем узлов в индексе.
Вот только узлы в индексе я — как разработчик — не вижу. А вершины в граф добавлять мне.
Потому что они имеют большую алгоритмическую сложность
Докажите.
меньшую наглядность.
А это субъективно.vintage
24.09.2015 00:53Если бы можно было написать нормальный обобщенный код, порождающий модель, соответствующую домену, программистов можно было бы выкинуть на свалку.
Вы улетели в стратосферу. Что мешает генерировать нормальные имена в духе «book.editor»?
И как следствие никак не описывает алгоритмы для работы с «дополнительными» данными.
А должна? К чему вы клоните?
Вот только узлы в индексе я — как разработчик — не вижу. А вершины в граф добавлять мне.
Вы их фактически создаёте налету в агрегирующем запросе. Из таблиц «инфа о книгах» и «инфа о фильмах» создаёте виртуальную таблицу «инфа о годе выпуска».
VolCh
22.09.2015 15:30+1Бизнес вообще документно ориентирован.
Бизнес обычно не документно ориентирован, документы, как правило, лишь средства отражения (учёта) состояния бизнес-процессов, модель по сути, по которой кто-то может узнать состояние бизнес-процессов на определенный момент времени (при условии, что документы составлялись в нужном объёме и фиксировали объективные состояния процессов).lair
24.09.2015 01:02Что мешает генерировать нормальные имена в духе «book.editor»?
Каждый раз что-нибудь новое.
А должна? К чему вы клоните?
К тому, что умение работать с документо-ориентированными данными для графа не свойственно.
Вы их фактически создаёте налету в агрегирующем запросе. Из таблиц «инфа о книгах» и «инфа о фильмах» создаёте виртуальную таблицу «инфа о годе выпуска».
Именно что виртуальную. Это сущность, которая появляется тогда, когда она нужна в отчете.vintage
24.09.2015 09:34К тому, что умение работать с документо-ориентированными данными для графа не свойственно.
Что такое «документно-ориентированные данные» и каким образом модель данных «граф» может работать?
Именно что виртуальную. Это сущность, которая появляется тогда, когда она нужна в отчете.
И что хорошего в том, чтобы создавать её при каждом запросе отчёта?lair
24.09.2015 11:11Что такое «документно-ориентированные данные»
Documents are the main concept in document databases. [...] These documents are self-describing, hierarchical tree data structures which can consist of maps, collections, and scalar values. The documents stored are similar to each other but do not have to be exactly the same.
каким образом модель данных «граф» может работать?
У каждой модели данных есть свои типовые операции, для которых она выгодна, набор операций, который на ней делать чрезвычайно неоптимально, и «всё остальное».
И что хорошего в том, чтобы создавать её при каждом запросе отчёта?
Отсутствие дублирования данных, например. Ну и вообще семантическая стройность.
VolCh
22.09.2015 15:22Сформулировать их пока не возьмусь, чисто интуитивно.
Какой-то конкретный год — объективно существующая сущность, период реального физического времени между двумя (пускай и субъективно выбранными) событиями. Год издания книги — это отношение сущности «книга» к сущности «год» по признаку того, что событие «издание» произошло в данный конкретный период времени. Это не свойство книги, не её наполнение, это её отношение к внешнему миру, такое же, как, например, «страна издания».lair
22.09.2015 15:29И вам читать про Партриджевскую парадигму «любое свойство есть отношение».
VolCh
22.09.2015 15:42Разницы между отношениями «в книге 500 страниц (книга состоит из 500 страниц)» и «книга издана в 2015 году (книга издана во время течения 2015 года» не чувствуете?
lair
22.09.2015 15:59Если я вдруг начал мыслить терминами «книга издана в 2015 году — это отношение „год издания“ между сущностями „книга“ и „год“», то я могу с успехом распространить это мышление на страницы, причем как минимум двумя способами.
(а) «книга» относится к классу «500 страниц»
(б) «книга» содержит 500 связей со страницамиVolCh
23.09.2015 07:24Второй вариант вполне встречается на практике )
lair
23.09.2015 09:08На практике встречается почти что угодно, вопрос частоты и удобства применения.
VolCh
28.09.2015 01:13На практике для генерации отчётов с ежедневной разбивкой по данным, имеющим частью естественного первичного ключа (реально используется суррогатный первичный ключ) датувремя я использую предгенерированную табличку из одного столбца report_date типа дата. Это результат анализа воможности получить нужный отчёт (с учетом денормализации) за время меньше минуты и пересчитать всю денормализацию на момент старта транзакции меньще чем за час на доступных ресурсах в пределах 4-х SQL-СУБД.
VolCh
19.09.2015 14:25Семантику этих «чисел» обеспечивают метаданные, лежащие поверх, и ограничивающие операции. Сейчас, наверное, все РСУБД поддерживают внешние ключи, как для ограничения множества допустимых значений, так и для распространения изменений. Семантически это эквивалентно ссылкам на объекты.
В том-то и дело, что не эквивалентно. Ограничения на значения и распространение изменений семантически означают именно ограничения и распространение, а при каждом запросе приходится указывать СУБД как две таблицы связывать, иначе в результат запроса попадёт результат их умножения, а не соединения, хотя в подавляющем большинстве случаев разработчики баз данных имеют в виду использование нескольких таблиц в одном выражении FROM исключительно для соединения исключительно по одной, заранее известной паре столбцов паре столбцов и даже косвенно сообщают эту информацию СУБД в виде ограничений, индексов и т. п., но СУБД их в целом игнорирует, воспринимая их только как прямые указания на создание ограничений и т. д., не понимая что, разработчик собирается эти таблицы использовать совместно исключительно соединив их по полям на которым наложены ограничения и, соответственно, не применяя оптимизаций (разве что на уровне кэшей), производя объединение при каждом запросе.lair
19.09.2015 22:41а при каждом запросе приходится указывать СУБД как две таблицы связывать, иначе в результат запроса попадёт результат их умножения, а не соединения, хотя в подавляющем большинстве случаев разработчики баз данных имеют в виду использование нескольких таблиц в одном выражении FROM исключительно для соединения исключительно по одной, заранее известной паре столбцов паре столбцов
Это ограничение не парадигмы, а языка запросов. Ничего не мешает написать иной язык запросов, который будет использовать существующие метаданные для получения желаемого эффекта. А SQL просто очень консервативен.
А с другой стороны… я правильно понимаю, что вы хотите чего-то навроде «есть таблицы Books и Authors, я хочу, чтобы когда я пишуSELECT * FROM Books, Authors
, система автоматически строила джойн»? Или чего-то другого?VolCh
22.09.2015 15:05Нет, это именно ограничение парадигмы, реляционной модели — в ней нет такой сущности как «связь или зависимость между кортежами (строками) отношений (таблиц)», а есть лишь независимые кортежи независимых отношений и операции над ними. Чисто теоретически типы атрибутов не ограничены примитивными типами и могут быть другими кортежами, но на практике атрибуты — примитивные значения, которые иногда используются разработчиком для ссылки на другие отношения.
В идеале вообще что-то вроде: SELECT Books.Title, Books.Authors.Name; добавляя нынешние FROM и JOIN лишь в случае необходимости изменения основного поведения.lair
22.09.2015 15:09В идеале вообще что-то вроде: SELECT Books.Title, Books.Authors.Name; добавляя нынешние FROM и JOIN лишь в случае необходимости изменения основного поведения.
Угу. Как ни странно, добрая половина ORM дает вам именно такое поведение, все еще имея внутри реляционный код. И для этого используются тривиальные метаданные. Причем, что характерно, O и M из ORM для этого не нужны, достаточно метаданных и конструктора запросов.VolCh
22.09.2015 15:44Ну так наличие таких инструментов как раз и говорит о том, что популярные реляционные СУБД не очень удобны в ежедневном использовании без подобных обёрток, зачастую скрывающих реляционную модель хранилища.
lair
22.09.2015 16:00Не «популярные реляционные БД», а «используемый язык запросов».
VolCh
28.09.2015 01:14Формально вы правы, на практике для популярных реляционных СУБД язык запросов означает SQL.
lair
28.09.2015 01:16Просто язык — это еще не парадигма. Точно так же, как не все описанные в посте особенности ориента надо переносить на графовые БД, так и не все проблемы SQL надо переносить на реляционные БД.
В DB/2, кстати, весьма зачетный внутренний язык был.VolCh
28.09.2015 02:55Повторюсь: формально вы правы. Я ещё 20+ лет назад писал запросы к реляционным БД на Сях без всяких намеков на SQL, чисто в терминах реляционной алгебры плюс хэндлеры. Но мэйнстрим таков, что РСУБД = SQL СУБД, как бы мы к этому не относились.
lair
28.09.2015 11:15Возможно, тогда надо прыгать в сторону развития языка, а не только отказа от РСУБД?
vintage
24.09.2015 01:14Примерно так и есть в OrientDB с той лишь разницей, что он автоматически не «уплощает» коллекции. То есть селект вида:
SELECT title , authors.name , authors.muses.name FROM Book
Вернёт записи вида:
( "Hello" , [ "John" , "Artur" ] , [ [] , [ "Elena" ] ] ] )
bigfatbrowncat
18.09.2015 16:22Сейчас меня тут, думаю, закидают помидорами, но поделюсь собственным впечатлением.
Программирую я давно — с самой школы. Так как начинал что-то писать более-менее серьезное в Delphi, то понятия ООП «впитал с малолетства». А так как задачки были ерундовые, с СУБД тогда дела не имел.
Поиметь дело с ними пришлось несколько лет назад, когда тяжелая судьба занесла меня в Java Enterprise. Зная неплохо Java (а до нее мея опыт в C# и C++), я впервые столкнуля с тем, что такое реляционная база данных. А еще что такое ORM Hibernate. Влетел, можно сказать, обеими ногами и увяз по колено.
И вот, что я могу сказать о своих первых впечатлениях (которые потом, по мере использования, только укрепились).
Я полностью согласен с автором этого поста в вопросах критики по отношению к РСУБД. Представление объектов и связей между ними таблицами — совершенно немыслимый костыль, который явно пришел в индустрию из тех времен, когда ООП было только в голове (в лучшем случае — на бумаге), но не в коде. Потому что идеальной (по моим представлениям) системой является такая, при которой данные, с которыми работает ПО, зеркалируются в долговременное хранилище незаметно для разработчика. И тут, явно, никакая дополнительная конвертация (тем более, интеллектуальная и требующая дополнительного проектирования) недопустима.
Долгое время я мирился с когнитивным диссонансом, выслушивая со стороны старших товарищей аргументы в духе «таблицы проще хранить, с ними быстрее работать» и т. д… Я просто пожимал плечами и верил, что они правы. А сейчас вижу, что и этот оплот разваливается (если верить статье). Надо попробовать попользоваться хоть немного этой самой OrientDB при случае. Жаль, что теперешняя моя работа от СУБД далека диаметрально.lair
18.09.2015 16:24+1А вы не верьте статье. Никуда РСУБД не разваливаются, просто для ряда задач они менее эффективны, чем другие хранилища. Пять-десять-пятнадцать лет назад доля таких задач была меньше (и выбор был меньше), сейчас она смещается (с повышением разнообразия и развитием альтернативных парадигм хранения).
bigfatbrowncat
18.09.2015 16:58-1Пять-десять-пятнадцать лет назад доля таких задач была меньше
В том-то и дело, что я такими задачами почти не занимался. Мне было интересно «использовать ООП наполную катушку».
Я прекрасно понимаю, что для задач типа складских «сводная таблица цена-количество-стоимость» табличное представление — самое верное и простое. Понятно, что таблицы хороши для представления однородных данных…
Но эти задачи давно уже все решены. Сейчас действительно актуальны Wiki и соцсети. Как то, так и другое редставляется жутко нерациональным, если организовывать данные в виде таблиц. Как составить графовую модель сети Facebook, я, думаю, с точностью незначительных нюансов, нарисую за полчаса. А вот как эти данные уложить в табицы… Тут без поллитры точно не разберешься. А если редставить себе, что будет использоваться еще и ORM, то вообще кирдык психике (видел я сложность Hibernate-овских запросов на сравнительно примитивной задаче).
Мне кажется, что основная причина, по которой все до сих пор держатся за реляционщину — страх перед ошибками. Вот если мне скажут «мы используем Oracle, потому что его 20 лет писали и чинили, а твою <вставьте слово> я впервые вижу», то я это вполне пойму. А +25% к размеру базы — это не цена за простую понятную и легко масштабируемую программу, как мне кажется.lair
18.09.2015 17:12В том-то и дело, что я такими задачами почти не занимался. Мне было интересно «использовать ООП наполную катушку».
Понимаете, это заведомо неправильный подход. «Интересно» — решать конкретную прикладную задачу, выбрав для нее тот инструмент, который для нее подходит. Это не всегда ООП, это не всегда РСУБД, это не всегда <что угодно другое>.
Я вот сейчас для себя пилю проектик, в котором три года назад использовал бы РСУБД (MS SQL), год назад — документо-ориентированную БД (RavenDB), а сейчас, в итоге, взял хранилище событий (EventStore), а по мере увеличения нагрузки планирую добавлять read models на том, на чем будет оправданнее.
Я прекрасно понимаю, что для задач типа складских «сводная таблица цена-количество-стоимость» табличное представление — самое верное и простое. Понятно, что таблицы хороши для представления однородных данных… Но эти задачи давно уже все решены.
О нет. Выработана общая стратегия решения таких задач, но сами задачи далеко не решены, иначе бы рынок ПО резко схлопнулся. Компаний (например), автоматизирующих свой складской учет — все больше, и больше, и всем им нужно ставить ПО, и у некоторых из них — нетиповые задачи.
Мне кажется, что основная причина, по которой все до сих пор держатся за реляционщину — страх перед ошибками.
Основная причина — это непонимание, как работают «новые» (на самом деле, нет) БД, нежелание разбираться, и нежелание искать выгодные стороны (я, конечно, говорю о новых проектах, с унаследованным ПО все веселее). Но я вот знаю одну (весьма авангардную) разработческую компанию, которая между мажорными версиями своего ПО сменила используемую СУБД с RavenDB (документо-ориентированная) на MS SQL (РСУБД) — просто потому, что их не удовлетворял опыт работы с Raven.
lair
18.09.2015 17:13Как составить графовую модель сети Facebook, я, думаю, с точностью незначительных нюансов, нарисую за полчаса.
Кстати, у ФБ — мультипарадигменная модель, там есть и графы, и документо-ориентированные куски. И это если не учитывать внутреннюю кухню, которую мы не видим.
Я, естественно, о бизнесе, а не о том, что они реализовали.
novoxudonoser
18.09.2015 17:28Не надо передёргивать про ORM, на питоне укладка вашей задачи в таблицы займет у меня ~ пол часа, так что всё с ними хорошо.
bigfatbrowncat
18.09.2015 17:45Укладка-то да. А вот понимание внутреннего устройства, отладка глюков «укладчика» и т д… ORM как всякая «умная автозабивалка» хорош ровно до тех пор, пока в него не приходится влезть, чтобы понять, где и почему он накосячил.
vogre
18.09.2015 20:39Обычно разобраться и починить глюк ORM в разы проще, чем смигрировать БД, особенно на БД с другой парадигмой.
svd71
18.09.2015 21:42У самого не малый опыт в базах данных. Тоже возникали подобные мысли о не совершенстве реляцилнных баз. Но есть непреодалимое «но». Называется оно «уровень абстракции». Наверное знаете про трех-звенную архитектуру построения. Вот в этой архитектуре, во второем слое (бизнес-логики) имеет место применять понятие сущьностей. Именно там их и удобнее всего принимать от клиента как сущьности и конверитровать в плоскую модель. И из плоской модели выдавать клиенту уже собранные сущьности.
Добавлю, что в текущей момент работаю с обычной двузвенкой (клинет-сервер), но сущьности использую только на стороне клиентской программы (программы управления роботизированным комплексом). Это и обеспечивает более логичный с точки зрения ООП код, при этом не возникает определенных сложностей и затыков разобраться в миграции данных и понять причину того или другого поведения комплекса.
Тоже можно сказать, что это часный случай. Но в том то все и дело, что любое применение того или иного инструмента является частным случает — в примере от ТС часный случай использования шуруповерта в качестве отбойника.vintage
18.09.2015 22:48Как же я обожаю эти метафоры — можно крутить-вертеть их с получением совершенно любых выводов :-)
В моей реализации бизнес сущности везде — и на клиенте, и на сервере, и в базе данных. И это, скажу я вам, крайне удобно и не слабо повышает эффективность трудозатрат. К тому же ещё сервер и клиент работают через один и тот же полиморфный js-api:
// передать управление салоном пользователю с id "cool-manager" salon.Manager().set( [ 'cool-manager' ] , [ myPerson ] ).then( managers => { console.log( managers.map( String ) } )
svd71
19.09.2015 14:57что от этого меняется? Скорость разработки? Чем больше я трачу времени на разработку, тем больше мне платят денег — это жизненный факт. Моим работодателям не нужно быстрее, им нужно чтоб работало без ошибок и сбоев, как и клиентов, которым они продают комплексы. Меня и так упрекают, что в отличии от своих коллег я очень быстро делаю свою работу — они не успевают за мной. Понимание взаимодействия сущностей? Все и так их прекрасно понимают, именно со стороны сущностей. А вот таблицы базы для них вторичны — просто хранилище данных из сущностей. Также как и контроллеры железки — они просто принимают эти хе сущности и отдают их же, абсолютно не интересуясь что там с базой данных и на каком она сервере крутится.
Так в чем же выигрыш?
Перевод в js-api для меня не делает погоды. Есть только один единственный модуль, который знаком с этой технологией — для обмена данных от внешнего клиента, чтоб переколбасить эти все данные во внутрениий, опримизированный и построеный для системы api и сформировать правильное сообщение в систему. Все. И то, если у клиентов совершенно другая система обмена сообщений (напрмер описанная на хабре HL7), то и этот модулек не будет использоваться.
Так подведем маленький итог нашей дискуссии: Сущности важны в основном процессе. Если у вас обработка(бизнес-логика) крутится непосретственно в базе — то тогда есть удобство использовать сущности. Иначе, любые конечные ветви взаимодествия извне полюбому упирается в плоскую передачу упорядоченных байтов, будь то обмен даххы наприме по tcp, хранение в бинарном файле или в РСУБД.vintage
21.09.2015 02:57У вас какие-то не правильные работодатели :-) В норме, бизнесу нужно как можно быстрее, потом как можно больше, потом как можно стабильней. Это не значит, что клиенту пойдёт ничего не умеющее падающее приложение. Это значит, что пощупать и внести коррективы можно будет как можно раньше, а не в последний день. Ну и лёгкая недоделанность во многих областях вполне допустима — многочисленные «вечные беты» тому пример.
Все-то, конечно всё понимают, да только получается как в известном анекдоте: https://hsto.org/files/8bb/23b/a3a/8bb23ba3aede496395ac3a63d42380f2.jpgsvd71
21.09.2015 07:44:D работодатели даже очень правильные. Немецкая компания выкупленная американцами. Так что они знают толк в производстве.
norguhtar
21.09.2015 08:52+1Зная неплохо Java (а до нее мея опыт в C# и C++), я впервые столкнуля с тем, что такое реляционная база данных. А еще что такое ORM Hibernate. Влетел, можно сказать, обеими ногами и увяз по колено.
Прежде чем лезть в такое изучите теорию и практику РСУБД. То что ORM текущая абстракция не знает только очень ленивый человек.
skey
18.09.2015 16:23Все больше это становится похоже на рекламную публикацию.
bigfatbrowncat
18.09.2015 16:59+3Вот вечно так. Написал человек от души о своей свежей и чистой любви, а ему — «хорош рекламу гнать» :)
vintage
18.09.2015 17:14Да были бы серьёзные альтернативы — я бы рассмотрел несколько таких СУБД, но сейчас пилят больше специализированные СУБД, чем универсальные. Я вообще хотел перевести ещё и части документации, где рассказывается про элегантную внутреннюю структуру, про лаконичную распределённую архитектуру (банально там даже узлы в пределах локальной сети сами друг друга находят через мультикаст и образуют кластер). Но потому прикинул, что сообщество всё равно этих трудов не оценит и сольёт карму за осквернение святынь и забил :-)
bigfatbrowncat
18.09.2015 17:46+1Пишите. Никто за переводные статьи карму не сливает. Я лично плюсану. Интересно.
vintage
18.09.2015 19:33Некоторые уже смекнули фишку и публикуют статью в англоязычном сегменте, а потом «переводят» её на Хабр :-)
bigfatbrowncat
19.09.2015 18:34Хм… не приходила такая идея в голову :) Я бы, наверное, поступил наоборот. Англоязычная аудитория же больше — сперва послушать критику соотечественников, перед тем как позориться на весь мир — как-то логичнее, к.м.к…
vintage
21.09.2015 03:03Англоязычная аудитория, как я слышал, более толерантная. А у нас за альтернативное мнение лишают возможности публиковать статьи. Вот и приходится прикидываться переводчиком, типа «мопед не мой, я просто перевёл». Кстати, случаем не посоветуете англоязычный ресурс для публикаций о программировании? :-)
bigfatbrowncat
21.09.2015 03:08+1Не посоветую, увы. Пока не нашел ничего подобного. Утешаю себя патриотической гордостью — полагаю, что аналога Хабра в мире нет.
Я не вполне согласен. У нас лишают возможности писать не за альтернативное мнение, а за отсутствие пиетета к авторитету большинства. То есть мнение-то каждый может иметь какое хочет, но высказать его должен, низко поклонившись, извинившись за наглость, хамство и прочие смертные грехи, а требований к объективности его суждений будет на порядок больше, чем к высказываемой большинством точке зрения.
Вот я, давеча, раскритиковал C++. Я его более-менее знаю, но совсем не люблю. Что там началось…
Ничего не поделаешь — традиционализм у отечественной интеллигенции в крови. Может, оно и к лучшему — иногда так проще и тверже стоять на ногах. Меньше риск внезапно оказаться «за бортом истории».
skey
18.09.2015 17:39+2Потому что:
— для меня является очевидным, что чем универсальнее инструмент, тем он более громоздкий и медленный. Почему вы не используете швейцарский нож для повседневного приема пищи?
— есть задачи, с которыми реляционные БД справятся лучше. Автор же предлагает использовать одну БД везде и всюду, судя по комментарию:
Возвращаться на реляционные — боже упаси
— и вот эта цитата:
Нет, я не буду рассказывать вам про MongoDB или ещё какую неполноценную «убийцу SQL».
Я расскажу вам про другого «убийцу SQL».bigfatbrowncat
18.09.2015 17:50Какое у вас восхтительное умение читать между строк.
Я в этой фразе:
Возвращаться на реляционные — боже упаси
увидел следующий смысл: «я ненавижу реляционные базы и мне неприятно ими пользоваться». Не меньше, но и не больше. Просто желание такое. При этом он всю дорогу говорит о том, что реляционные БД используются в случаях, когда они неэффективны. Где он что-то писал типа «не используйте реляционные базы НИКОГДА»? Посыл статьи — не использовать их там, где они неудобны. И много восторга от того, как это хорошо у него самого получилось.
Я расскажу вам про другого «убийцу SQL».
Юмор у всех разный. Один пошутил, другой не понял…skey
18.09.2015 17:52+1Где он что-то писал типа «не используйте реляционные базы НИКОГДА»?
В заголовке
vintage
18.09.2015 17:51+1Почему вы не используете швейцарский нож для повседневного приема пищи?
Потому же почему вы не пользуетесь всеми этими приборами для повседневного приёма пищи:
есть задачи, с которыми реляционные БД справятся лучше. Автор же предлагает использовать одну БД везде и всюду, судя по комментарию:
Озвучьте эти задачи, пожалуйста. Автор утверждает, что графовые СУБД справляются с задачами реляционных лучше, чем реляционные с задачами графовых, так что нет смысла ограничивать себя таблицами, если можно сразу рисовать графы.
Я расскажу вам про другого «убийцу SQL».
Про полноценную убийцу SQL.
musicriffstudio
18.09.2015 18:01+1по сравнению со статьёй "Как работает реляционная БД " выглядит как-то… непрофессионально, что ли. И магии нет.
maxru
18.09.2015 18:24+1Они не удовлетворяют требованиям ACID (Атомарность, Согласованность, Изолированность, Надёжность). OrientDB этим требованиям удовлетворяет.
Обоснуйте по каждому пункту, пожалуйста. Желательно с примерами.vintage
18.09.2015 18:33-2maxru
18.09.2015 18:44+6Отличное чтиво.
Не прочитал и страницы, как наткнулся на раздел:
Breaking of ACID properties when using remote protocol and Commands (SQL, Gremlin, JS, etc)
Т.е., как и монга «в целом ACID, но иногда не ACID»
Про «Durability», авторы, похоже, не совсем понимают, что это вообще означает, т.е. цитату из wikipedia они приводят, конечно, но смысла её не понимают, судя по следующей цитате:
If you're using an OrientDB Server connected remotely, if your application crashes the engine continue to work, but any pending transaction owned by the client will be rolled back.
vintage
18.09.2015 19:07Там транзакции хранятся на клиенте, да. Так что при падении этого клиента транзакции, очевидно, отменяются. Не очень понял, чем это не соответствует ACID, но монга вообще транзакции не умеет.
maxru
18.09.2015 19:12+2Приятно, что монга не умеет чего-то, что вроде как умеет ориент.
Ваша цитата, к какой части моего комментария относится?vintage
18.09.2015 19:15К обеим, они же об одном и том же вроде как :-)
maxru
18.09.2015 19:54Отнюдь. Durability — это не про автоматический откат транзакций.
vintage
18.09.2015 20:03Это про то, что если транзакция прошла, то она никуда не денется. И в конце даётся капитанская ремарка, что если транзакция не успела пройти и произошёл сбой приложения, то и незавершённая транзакция будет потеряна.
norguhtar
21.09.2015 08:53Транзакции на клиенте? ACID хранилище? АХАХАХАХАХА
vintage
21.09.2015 13:12До коммита они хранятся на клиенте.
norguhtar
21.09.2015 13:34Иии? Вот дальше пошла передача на сервер, в середине этого действа происходит обрыв связи. Что наблюдаем на сервере?
vintage
21.09.2015 14:02Ничего. Транзакция посылается единым пакетом.
norguhtar
21.09.2015 14:05Следующий вопрос. Пока идет проводка транзакции на сервере, и я в этот момент запрашиваю эти данные, что я увижу?
vintage
22.09.2015 01:20А что вы ожидаете увидеть?
norguhtar
22.09.2015 06:35А почему вы отвечаете вопросом на вопрос? :) Причем тут что я ожидаю увидеть. Вопрос состоит что будет на сервере. Если на сервере эти данные пишутся транзакционно, то зачем транзакции на клиенте?
vintage
22.09.2015 10:50А почему вы спрашиваете? Чтобы не напрягать сервер тем, что возможно и не надо будет коммитить.
maxru
18.09.2015 18:33Некоторые, особо «передовые» программисты, предлагают хранить каждый тип моделей в своей СУБД. «Важные данные» в реляционных, деревья в графовых, а примитивные вообще в словарях. Но подобные подходы вида «всякой задаче свой инструмент» лишь добавляют головной боли (и как следствие багов разной степени тяжести) на тему консистентности данных в разных частях приложения.
Заявление с апломбом, а факты где?vintage
18.09.2015 19:12-4Если это не очевидно, даже после чтения комментариев выше, то можете просто игнорировать этот пассаж :-)
maxru
18.09.2015 19:47+3Если у вас головная боль от размышлений на тему консистентности — подберите себе другую профессию.
vintage
18.09.2015 20:06+1«Многие из вас знакомы с достоинствами программиста. Их всего три, и, разумеется, это лень, нетерпеливость и высокомерие.» (с) Larry Wall
maxru
21.09.2015 14:19+3«Лень — двигатель прогресса»
«Упаси вас Бог от общения с людьми, которые не предлагают аргументов, а сыплют не подтверждёнными цитатами слабо известных им людей» (с) Цицеронvintage
22.09.2015 01:29-2«Главная проблема цитат в интернете в том, что люди сразу верят в их подлинность» В.И. Ленин
Andrii_Z
19.09.2015 00:24+3Еще один не осилил SQL?
Автор, а вы знаете, что для реляционных СУБД есть стройная реляционная алгебра? То есть корректность построений можно проверить математически.
Можно ли проверить корректность вашей модели?
Или «мамой клянус, правильно работает!»vintage
19.09.2015 10:47Автор упомянул её в первом жа абзаце. И часто вы пишете комментарии прочитав лишь один заголовок? :-)
Можно пример этой «математической проверки корректности»?
lair
19.09.2015 12:35+1Хм. Любопытно. А как, бишь, Orient (да и другие графовые БД) обеспечивает двустороннее прохождение по связи за одинаковое время и одинаковыми запросами?
grossws
19.09.2015 17:09И сколько это стоит CPU, RAM и HDD… То на некоторых задачах предпосчитанные join'ы в какой-нибудь кассандре прекрасно работают, хотя памяти и понимания структуры данных требуют чуток побольше.
norguhtar
21.09.2015 08:54Основная моя претензия к NoSQL СУБД это одна единственная вещь. Как по ней строить аналитику? Вот по РСУБД весьма просто, а как приходим в NoSQL то начинаются танцы с бубном.
lair
21.09.2015 11:27Вот именно поэтому NoSQL чаще рассматривают в контексте polyglot persistence. Но в принципе, теми же инструментами можно и на самой nosql базе построить хранилище под отчеты.
norguhtar
21.09.2015 13:35Но в принципе, теми же инструментами можно и на самой nosql базе построить хранилище под отчеты.
Угу и каждый раз свое.lair
21.09.2015 13:38Ну да. В паре случаев это даже будет удобнее.
Не, я не рекомендую так всегда делать, я просто говорю, что у этого конкретного недостатка есть механизмы компенсации.
vintage
22.09.2015 01:45А в чём сложности с NoSQL?
norguhtar
22.09.2015 06:32В том что аналитику вы по этим данным можете построить с трудом и каждый раз придется писать код.
vintage
22.09.2015 10:58+2Мне кажется вы неправомерно экстраполируете свой опыт работы с некоторыми NoSQL решениями на все нереляционные СУБД.
norguhtar
22.09.2015 11:13Я пока не видел ни одной NoSQL СУБД где это не требовалось. Да у части есть SQL подобный язык для аналитики, но как правило его возможности весьма слабы и что-то сложное из него не получить.
lega
30.09.2015 11:10create property Person.friend linkset Person
Я где то вычитал, что если переместить документ на который ссылаются через link*, то эта связь ломается. А если в документ добавлять данных и он выйдет за пределы первоначально ему отведенные, то этот документ подлежит перемещению (из mongodb).
Т.е. мы либо не можем расширять документы, либо ломаются связи.
Так ли это, как это «обруливается»?
Или забыть про link* и использовать edge?vintage
30.09.2015 13:21+1The record never loses its identity unless it is deleted. Once deleted its identity is never recycled (but with «local» storage). You can access a record directly by its RecordID. For this reason you don't need to create a field as a primary key like in a Relational DBMS.
http://orientdb.com/docs/2.1/Concepts.html#recordid
Как обруливается точно не знаю, но предполагаю, что так: в файлах *.cpl хранятся собственно данные, которые могут менять своё положение при изменении размеров, а в файлах *.cpm — маппинг идентификаторов на смещения в cpl-файлах. То есть да, получается некоторый индекс с O(1) по идентификаторам (массив со смещениями). И нет, это не то же самое, что первичный ключ в РСУБД и той же Монге, где значение этого ключа можно указывать своё, а не строго автоинкремент, из-за чего вместо массива приходится использовать более сложные структуры данных, допускающие пропуски.lega
30.09.2015 15:55+2Сделал тест «на коленке», 100к user(name, parent), база маленькая — долго ждать неохота, заливалось в 4 раз медленнее чем в mongo, но это не важно.
Цель — протестировать скорость ссылок «select name, parent.name from User», 100 запросов по 100 документов в каждом + в каждом документе ссылка на родителя, в случае с монгой — родители достаются последующим запросом:
OrientDB: ~1.4 сек
MongoDB: ~0.09 сек
Если из OrientDB выбирать без ссылок «select name from User», то выходит ~1.2 сек, возможно ссылки «быстрые», но общей картине это не помогает — OrientDB сам по себе медленный.
Т.е. если я буду делать join через ключи в монге, то все равно выходит быстрее чем через ссылки в OrientDB. Большие объемы в этом тесте не помогут OrientDB, т.к. используется SB-Tree для выборки.
Возможно (сложные) графы оправдали бы OrientDB, но они мне не часто встречаются, те что встречаются обычно решаются «в лоб» (иногда даже без джойнов).vintage
01.10.2015 00:11«На коленке» можно легко и противоположных результатов добиться :-) Например, MongoDB по умолчанию не дожидается записи в журнал, чтобы ответить «спокойно, я всё сохранила». В купе с отсутствием транзакций, вы легко можете потерять консистентность данных при падении субд. Если настроить, чтобы она отвечала лишь после сброса журнала на диск, то монга тут же становится в два раза медленнее на инсертах, чем ориент. Про селекты — нужны подробности как вы делали «100 запросов по 100 документов». Судя по такой большой разнице, подозреваю, что к монге обращались через курсор, а к ориенту — через 100 запросов да ещё и со смещением.
Покажите свой код. Вот мой: https://github.com/nin-jin/dbench
grossws
01.10.2015 01:19By default, all write operations will wait for acknowledgment by the server, as the default write concern is WriteConcern.ACKNOWLEDGED.
Write operations that use this write concern will wait for acknowledgement from the primary server before returning. Exceptions are raised for network issues, and server errors.
vintage
01.10.2015 01:55Acknowledged write concern does not confirm that the write operation has persisted to the disk system.
With a journaled write concern, the MongoDB acknowledges the write operation only after committing the data to the journal. This write concern ensures that MongoDB can recover the data following a shutdown or power interruption.
http://docs.mongodb.org/manual/core/write-concern/grossws
01.10.2015 03:23Да, согласен. С fsync журнала, да ещё и при одиночных записях тормозить будет. Тогда стоит сравнивать с batch insert'ами, т. к. journaled ждёт ближайшего fsync'а журнала, и, если сама запись пройдёт быстро, то это просто тупое ожидание следующего тика таймера. По умолчанию 100 ms, если журнал и основная база лежат на одном диске, что много больше стандартного insert'а.
lega
01.10.2015 02:49+1Например, MongoDB по умолчанию не дожидается записи в журнал, чтобы ответить «спокойно, я всё сохранила».
Это не влияет на скорость записи в бд, влияет на скрипт, будет он ждать или нет ответа и скорость отправки последовательных операций.
Для проверки OrientDB я запускал 10 потоков, OrientDB кушал ~95% cpu, т.е. выдавал все что мог, поэтому ожидание в скрипте не влияло.
В купе с отсутствием транзакций
Да, транзакции — серьезный фактор, поэтому ArangoDB стоит в списке на рассмотрение.
Вот кусок кода, для OrientDB один запрос без смещения, на поле name сделан индекс SB-Tree, без индекса работает в 400 раз медленнее — т.е. индекс работает.
Тесты запускал в 1 поток, сейчас запустил в 10 потоков (итого 1000 запросов по 100 документов):
OrientDB: ~7.3 сек
MongoDB: ~0.4 секlega
01.10.2015 02:55будет он ждать или нет ответа и скорость отправки последовательных операций.
Запись без ожидания ответа, не считая последнего документа, который ждет ответа записи, что означает что запись завершена.vintage
01.10.2015 03:50Это не влияет на скорость записи в бд, влияет на скрипт, будет он ждать или нет ответа и скорость отправки последовательных операций.
Ну да, это влияет на бенчмарки :-)
parents = db.user.find({'_id': {'$in': list(parents)}})
Я так понимаю тут возвращается курсор и нужно развернуть его в список:
parents = list(db.user.find({'_id': {'$in': list(parents)}}))
Что показывает explain?
100 запросов вы делаете разные или одинаковые?lega
01.10.2015 15:59Я так понимаю тут возвращается курсор и нужно развернуть его в список:
Упс, пропустил, в первой версии был пербор в цикле, поправил (стало медленнее в 2 раза ~0.18 сек), сделал новый набор данных — увеличил кол-во родителей:
OrientDB: ~1.7 сек
MongoDB: ~0.4 сек
Завернул тест в docker для тех кто хочет попробовать у себя, запускать так:
git clone https://github.com/lega911/db_test0 cd db_test0 ./init.sh ./fill.sh ./start.sh
Для запуска нужен docker и github, если порты 2424, 2480, 27020 уже заняты, их можно сменить в init.sh либо вырезать совсем, кол-во документов можно сменить в fill.shlega
01.10.2015 17:51Запустил тест на Digital Ocean (20$), в один поток и в 10:
OrientDB: ~6 сек и ~18 сек
MongoDB: ~1.3 сек и ~3.8 сек
Запустил на 1М документов, если курсоры не отвалятся то выложу результат.lega
01.10.2015 21:40+1Перемерял 100k на серверах Амстердама и Нью Йорка с отключением конкурирующего контейнера:
100k
mongodb: 0.6s, 3s
orientdb: 4s, 16s
1M
mongodb: 0.9s, 3.5s
orientdb: 5s, 18s
vintage
02.10.2015 17:05+1Да, похоже выборки по индексам в несколько раз медленнее. Я обновил свои тесты (https://github.com/nin-jin/dbench) — теперь они тоже заводятся из под докера. На 100К записей у меня получилась выборка по индексам у ориента в 2 раза медленнее, чем в монге и постгресе, а выборка связанных записей в постгресе в 2 раза быстрей, чем в монге и ориенте. Потом проверю динамику изменения скорости в зависимости от объёма данных и прикручу многопоточность (сейчас сто волокон, но одна нить).
vintage
02.10.2015 17:35Кстати, монга скушала в два с половиной раза больше места на диске, чем ориент (монга хранит имена всех полей, а ориент не хранит имена полей, которые заданы в схеме), а ориент в 4 раза больше, чем постгрес (в постгресе не хранятся коллекции детей, вместо этого добавлен индекс по родителям — тут правда есть косяк, не сохраняется порядок комментариев).
lega
02.10.2015 22:19Добавлю пару комментов в защиту монги:
--journalCommitInterval 2
Это видимо что-бы монга медленнее добавляла данные, а для надежности в реальных проектах просто делают реплику. А в orientdb и postgresql какой интервал сброса на диск (не в кеш ОС)?
Ну да ладно, речь про чтение,
а выборка связанных записей в постгресе в 2 раза быстрей, чем в монге и ориенте.
Потому что там та же выборка диапазона по индексу (что и в первом тесте). В монге можно сделать так же (doc.parent) и она будет такой же быстрой, т.е. монга дает варианты где у каждого свои плюсы, минусы. То же самое можно сделать и в orientdb, но он медленнее (судя по первому тесту), кстати в postgresql тоже можно запихнуть массив, в json*.vintage
03.10.2015 01:03Это видимо что-бы монга медленнее добавляла данные, а для надежности в реальных проектах просто делают реплику.
Нет, это чтобы быть уверенным, что данные не потеряются. Реплика тут ничем не поможет (пример — нода отвечает, что сохранила и тут же падает, не успев реплицировать).
А в orientdb и postgresql какой интервал сброса на диск (не в кеш ОС)?
Без понятия, но увеличение его для монги погоды не делало.
В монге можно сделать так же (doc.parent) и она будет такой же быстрой
И также придётся париться с сохранением порядка комментариев, которое я поленился пока реализовывать для постгреса, а надо прикрутить для чистоты эксперимента.
кстати в postgresql тоже можно запихнуть массив, в json
Через костыль в виде hstore? Ну да, можно. Прелесть ориента в том, что можно иметь приемлемую скорость и хороший потенциал горизонтального масштабирования, не вывихивая себе мозг и не утапливая проект в грудах запутанного кода. Банально, в админке, чтобы перейти к связанной сущности достаточно кликнуть по ссылке, а не писать sql запрос — это значительно упрощает и ускоряет дебаг, так как связи между сущностями явные.vintage
03.10.2015 01:38А, нет, postgres уверенными темпами движется в сторону монги :-) http://www.postgresql.org/docs/devel/static/datatype-json.html
В поле можно хранить json-документ, по нему можно даже некоторые индексы построить. Правда валидация идёт лесом, памяти больше ест и запросы похожи на перловые заклинания.
lega
03.10.2015 11:51Реплика тут ничем не поможет (пример — нода отвечает, что сохранила и тут же падает, не успев реплицировать).
В монге как раз это продумано, вы при записи указываете сколько нод «запишет» ваш документ прежде чем вы получите ответ, например при w=2 — минимум две ноды получат документ прежде чем вы получите ответ о записи (при этом даже можно журналирование отключить).
А в случае с журналированием (что и в одиночном postgresql/orientdb) вы как раз имеете период когда данные еще не сбросились на диск.
И также придётся париться с сохранением порядка комментариев
Не для всех задач нужен порядок, (например комменты можно посортировать уже на клиенте), даже если добавить поле очередности комментов — оно все равно будет быстрее чем doc.child т.к. будет выборка одного диапазона из индекса (как в первом тесте).vintage
03.10.2015 12:45Если не пугает перспектива потерять данные при обесточивании обеих нод, тогда проще in-memory базы поднять и к диску вообще не обращаться, кроме как для свопа и бэкапа ;-)
В отношении родитель-дети порядок обычно имеет значение. Я уже добавил постгресу отдельное поле для указания порядка — инсерты стали занимть по времени столько же, сколько и в ориенте. На селектах, конечно, почти не отразилось.
Ещё добавил графовое апи для ориента — оно раза в два медленнее при записи и при переходах по ссылкам.lega
03.10.2015 13:37Если не пугает перспектива потерять данные при обесточивании обеих нод
Шанс потерять данные при любом подходе есть, хоть и мизерный, что-бы снизить риск обесточивания «обеих» нод, их размещают в разных ДЦ.
На селектах, конечно, почти не отразилось.
Как я и предположил.
Я уже добавил постгресу отдельное поле для указания порядка — инсерты стали занимть по времени столько же, сколько и в ориенте
Вместо инкремента, который будет кривой в случае удаления комментов, можно писать timestamp, тогда будет быстро как в изначальном варианте (тем более поле «время» обычно есть у комментариев любого проекта).vintage
03.10.2015 15:27Только вот дожидаться реплики из другого ДЦ придётся дольше, чем от сброса журнала на диск.
Временная метка ничем не лучше айдишника. Проблемы начинаются при переносах веток. Конкретно для комментов это не очень актуально, но обычно порядок элементов в списках всё же не зависит от времени создания этих элементов.lega
03.10.2015 18:09Только вот дожидаться реплики из другого ДЦ придётся дольше, чем от сброса журнала на диск.
Сейчас померял пинг из Амстердама (Digital Ocean) до Франкфурта (Leaseweb) = 1 — 1.5ms
ping64 bytes from 185.28.68.36: icmp_seq=1 ttl=59 time=1.33 ms
64 bytes from 185.28.68.36: icmp_seq=2 ttl=59 time=1.10 ms
64 bytes from 185.28.68.36: icmp_seq=3 ttl=59 time=1.12 ms
64 bytes from 185.28.68.36: icmp_seq=4 ttl=59 time=1.09 ms
64 bytes from 185.28.68.36: icmp_seq=5 ttl=59 time=1.05 ms
64 bytes from 185.28.68.36: icmp_seq=6 ttl=59 time=1.23 msvintage
03.10.2015 20:35-3Если данные не страшно потерять, то зачем их вообще писать? Логи ведь не просто так пишутся.
grossws
03.10.2015 23:11Возникает ощущение, что вы притворяетесь.
Разные данные имеют разную ценность, что, вроде, очевидно. Вы же не будете для хранения промежуточных данных, которые пересчитываются за час 5 дубликатов в 5 разных az/dc, если у вас допустима такая задержка (на пересчёт)?
lega
03.10.2015 23:37У меня был проект, где не страшно было потерять сотню, другую из миллиарда, на итоговую статистику не влияло. Если писать без оповещения, это не значит что данные не запишутся, они пишутся так же как и с оповещением, а если монге плохо* то операция без оповещения выдаст ошибку. На практике проблем с этим нет.
Монга просто дает разные варианты (в отличие от других*), вы уже сами определяете что вам нужно.vintage
04.10.2015 12:58Статистику можно собирать и не создавая миллиарды записей в базе. Я же говорил про те логи, которые помогают «расследовать происшествие», а не просто «массовка для статистики».
Я не сторонник половинчатых решений с неопределённым поведением. Если мне не важно записались ли данные, то я продолжу исполнение вообще не дожидаясь ответа от субд. Если же я дожидаюсь ответа, значит мне важно, прошла ли запись успешно, и если нет, то ожидаю получить информацию о произошедшей исключительной ситуации, какой бы она ни была. А не так, что «палка иногда стреляет, но редко и тихо».lega
04.10.2015 15:06Если мне не важно записались ли данные, то я продолжу исполнение вообще не дожидаясь ответа от субд. Если же я дожидаюсь ответа, значит мне важно, прошла ли запись успешно, и если нет, то ожидаю получить информацию о произошедшей исключительной ситуации, какой бы она ни была.
Вы как раз и описали работу с монгой, но у вас почему-то какая-то претензия.vintage
04.10.2015 21:02Претензия у меня к тому, что по умолчанию монга торопится сказать, что записала, хотя по факту ещё нет. Но это исправимо настройками. А вот атомарность на уровне документа, а не всей базы — это уже не исправимо и приходится либо плясать вокруг двухфазных коммитов (что ещё в два раза замедлит её на запись), либо иметь ввиду, что данные в базе будут иногда разъезжаться.
whitepen
30.09.2015 11:33-2Да, хорошо иметь банк данных, где будет и то, и это, и еще вон то. Да вот беда, кто бы не вводил эти данные, непременно сделает ошибку, да мало того, еще и специально напортит. Конечно, как ведь хорошо расположить базу деревом, вон файловая система и есть дерево — чем не база? В файловой системе есть еще и ссылки. Задание ответственному работнику: пойди ка, милай, проверь дерево базы данных со ссылками много ко многим на предмет соответствия реальному положению дел. Зачем нужна база данных, где сущности ветвятся себе как джунгли и только гуру-сталкер знает что где лежит, правда он уже пять лет на пенсии? Реляционные базы живы потому, что живой человек может контролировать данные в таблицах, и только в таблицах, и ни в чем, кроме таблиц — фамилия-адрес, фамилия-адрес. А всякие там ораклы путем весьма запутанных противоречивых алгоритмов пытаются такую уродливую форму хранения данных как то там обработать. Считается что конечному пользователю все должно быть просто и понятно, а программист пусть выкручивается как хочет — его проблемы ваще никого не волнуют. В базе все по прежнему — достоверность данных важнее всех остальных свойств вместе взятых.
nekipelov
Наверное СУБД — это все же инструмент. И в зависимости от задачи мы берем тот или иной инструмент (это кстати и к голосованию относится). Универсальных СУБД не существует.
vintage
Обоснуйте, пожалуйста :-)
Largo
Возьмите шуруповёрт и попробуйте им проперфорировать бетонную стену. Тоже самое в случае с базами.
vintage
Прогресс не стоит на месте :-)
vintage
Или вот ещё один универсальный инструмент, который я недавно себе приобрёл:
lair
Угу, а у меня на кухне две разных ступки с пестиками, и сковороды из трех разных металлов. А вы обходитесь «универсальными инструментами».
vintage
Никак не могу уловить какую мысль вы пытались этим донести :-)
lair
То, что для каждой задачи — свой инструмент. Чем универсальнее инструмент, тем, скорее всего, хуже он выполняет каждую отдельную задачу по сравнению со специализированным.
vintage
Тем больше вам нужно инструментов для выполнения разных задач. Тем больше вероятность получить несовместимость, несогласованность. Тем больше точек отказа. Вы только подумайте, что бы было, если бы для выполнения каждой задачи у нас с вами было по отдельной специализированной руке :-)
lair
У меня в каждый конкретный момент задачи ограничены.
… и тем меньше опасность отказа каждой точки.
vintage
> У меня в каждый конкретный момент задачи ограничены.
Только ящик с инструментами бездонный :-)
> … и тем меньше опасность отказа каждой точки.
Тем больше вероятность отказа хотя бы одной точки. Так и будете спорить с тем, что простые решения надёжней? :-)
lair
Не вижу в этом ничего плохого. Особенно в случае с ПО.
Понятие «надежности» нынче не так однозначно, как вам кажется. Какая система «надежнее» — та, которая падает с вероятностью 25%, но вся, или та, в которой с вероятностью 50% происходит потеря части функциональности?
vintage
Я понимаю, что попираю устои, но вы не могли бы вести себя менее спесиво? Спасибо.
Та, в которой не происходит при этом потеря данных и их согласованности :-)
lair
Вместо того, чтобы тратить его на попытки забить гвозди гантелей. Я считаю, это выигрыш.
Для простоты — в обеих.
vintage
В одной ACID СУБД потерь не будет. Но если вы будете использовать «на каждый чих свой инструмент», то без услуг СУБД без ACID явно не обойдётесь.
lair
Вы не знаете, что, где и как я делаю.
А эта ваша мультимодельная СУБД умеет реляционную модель?
(А вы все еще держитесь за ACID?)
Вопрос был не в этом, а в том, что есть две системы с разными вероятностями отказа (и последствиями этого отказа). Для простоты обсуждения ACID-гарантии у них одинаковые. Какая из них «надежнее»?
vintage
А чего б не держаться за хорошие вещи?
При прочих равных комбинация двух технологий не может быть надёжней одной. OrientDB, например, образует аналог RAID но для баз данных, так что отказ одного узла не фатален.
lair
Она еще и индексные оптимизации не умеет (если я, конечно, ничего не путаю).
Та самая ситуация, когда вы мне предлагаете шуруповерт вместо перфоратора… а у меня несущая бетонная стена.
Стоимость реализации?
А откуда вы взяли «комбинацию двух технологий»? Я, вроде бы, говорил о системе в целом.
vintage
Индексные оптимизации — это вы о чём?
Нет нет, если у вас такая прочная стена, то вам стоит в дополнение к универсальному шуруповёрту приобрести перфоратор. А вот дрель можно и не покупать.Если стоимость данных меньше стоимости ACID, то да, можно и поиграть с ненадёжными инструментами :-) Но по мне так чем меньше непредсказуемости тем лучше, так что без веских аргументов я бы не стал отказываться от ACID.
Система в целом состоит из разных задач. А к каждой вы предлагаете индивидуальный подход. Я же говорю, что есть инструменты, которые без лишнего оверхеда позволяют решать сразу несколько типов задач. Что в этом плохого — ума не приложу.
lair
Вот об этом:
Работает себе из коробочки полным перебором таблицы. Стало медленно — построили индекс, и внезапно — не трогая кода! — стало быстрее в разы.
Вы так говорите, словно кроме ACID надежных инструментов не бывает.
Вот «без лишнего оверхеда» — еще надо доказать.
Но речь здесь шла не о том, а о простом вопросе «как меняется надежность системы с увеличением числа точек отказа». Я привел конкретный пример — вы до сих пор не можете ответить, что происходит с надежностью системы.
vintage
Ориент тоже поддерживает индексы разных типов: orientdb.com/docs/last/Indexes.html
ACID — это и есть различные аспекты надёжности, без которых данным полученным из БД нельзя доверять.
Мы ходим по кругу. Мне нечего добавить к тому, что я уже сказал.
lair
Какой-то из них работает так, как описано в моем примере?
Вот только ACID на распределенных системах на редкость дорог, и поэтому чаще не используется, чем используется. Но вы все равно пользуетесь этими системами (и доверяете им). И даже на не-распределенной БД можно жить без полноценного ACID. С ним, конечно, легче (пока вы не строите высоконагруженную систему), но и без него можно.
vintage
Разумеется.
Он дорог лишь при большом числе реплик, но не шардов. Ориент позволяет гибко настроить как кластеры (наборы однотипных узлов данных) раскидываются по узлам (инстансам субд).
lair
Я так понимаю, это про индексы… вы, конечно же, можете показать, где в документации написано, что с момента построения индекса по полям все запросы по этим полям автоматически попадают в индекс?
Ровно наоборот. Количество реплик не влияет на стоимость ACID (если вы, конечно, не включаете в ACID write-quorum, которого там не было изначально). А вот каждый шард — это, потенциально, новая нода в распределенной транзакции.
(да, а еще бывают распределенные транзакции между несколькими экземплярами/системами)
vintage
Куда ж без него? Если кворум не будет достигнут, то транзакция не пройдёт, а мы уже отчитались, что прошла.
А реплика — гарантированная новая нода в распределённой транзакции.
А мы сейчас о чём говорили?
lair
Потому в документации написано, что обращение к индексу делается через префикс, и нигде не написано иного. Если это не так — прекрасно.
Это если кворум на запись больше единицы.
Только если вы используете стопроцентный кворум на запись.
Об операциях внутри одной системы (потому что и реплики, и шардинг — это одна система).
vintage
Если кворум меньше большинства.
Имеются ввиду транзакции между разными СУБД? Ну, я про такие не слышал. Разве что через приложение.
lair
Это само по себе ни о чем не говорит и ничего не обещает.
Эээ… вы как-то по-своему понимаете кворум. Write quorum — это число реплик, которые должны рапортовать, что запись прошла успешно, прежде чем она будет признаной успешной системой в целом. Большинство тут ни при чем. Соответственно, транзакция становится распределенной в тот момент, когда write quorum больше единицы.
Между разными системами — СУБД не единственный транзакционный ресурс.
А зря. Они есть, и они составляют немалую головную боль.
vintage
Транзакция становится распределённой, когда затрагивает несколько узлов. Моё замечание про большинство касалось случая отката транзакции. Если вы не дожидаетесь завершения транзакции (writeQuorum < majority), то получаете нарушение Durability.
Не слышал — в смысле реализаций такого в СУБД, а не вообще.
lair
В MS SQL есть, например. Другое дело, что все равно эта реализация рано или поздно упирается в ограничения (или принципиальную невозможность), и вы вынуждены делать систему, не имеющую ACID в одной из точек. После этого, внезапно, становится понятно, как работать с системами, которые имеют очень ограниченные ACID-гарантии.
vintage
И как же, например?
lair
Через компенсации и eventual consistency. Если грубо, то аналогично тому, как проходят списания по пластиковым картам.
vintage
Ну то есть путём усложнения процессов. В случае гетерогенных систем это необходимость. Но стоит ли самому себе вставлять палки в колёса?
lair
Во-первых, почти любая сложная система в бизнесе — гетерогенная (по крайней мере, в моем опыте всегда получалось так). Во-вторых, ей достаточно быть распределенной (две БД одного производителя, не состоящие в кластере), чтобы эти проблемы начали проявляться.
В-третьих — CAP-«теорема».
vintage
Поэтому давайте напихаем побольше разных no-acid систем, чтобы «всё как у взрослых»? :-)
Вот именно, что «теорема» :-)
lair
Нет, поэтому давайте не будем ограничивать себя только теми архитектурами, которые дают ACID в границах системы.
Опровергнуть ее тоже пока никому не удалось. Собственно, OrientDB ей удовлетворяет.
vintage
И всё же тем, что дают ACID стоит, отдать предпочтение.
(http://habrahabr.ru/post/231703/)[Давайте не будем снова вспоминать эти глупости.] :-)
lair
Ну да, нам всем хочется жить в идеальном мире.
Ничего глупого в CAP нет. Она просто помогает правильным образом понимать некоторые компромисы.
vintage
Скорее запутывает, внося неожиданные определения привычных терминов.
lair
Множественное число лишнее — только consistency. Ну и да, ничего неожиданного в использованном там определении, если смотреть на распределенные системы, нет.
В частности, как уже говорилось, Orient не поддерживает consistency в понимании CAP-теоремы, и при этом еще и отказывается от availability при сетевом отказе… так себе компромис, будем честными.
vintage
В Ориенте это всё гибко настраивается: http://www.slideshare.net/lvca/orientdb-distributed-architecture-11
lair
Его можно сделать полностью строго консистентным при распределенной архитектуре? А как тогда понимать следующую фразу из документации:
vintage
«In case one or more nodes fail on commit, the quorum is checked. If the quorum has been respected, then the failing nodes are aligned to the winner nodes, otherwise all the nodes rollback the transaction.»
Ну то есть, если не используются локи и master-slave конфигурация, то такая ситуация вполне возможна из-за конкурирующей транзакции.
lair
А если используется мастер-слейв, и связь между мастером и слейвом нарушена — что будет при записи?
vintage
На сколько я понимаю слейв будет выкинут из кластера и все клиенты переподключатся к мастеру.
lair
… это если мастер доступен оттуда, откуда клиенты стучались к слейву.
Но, как видите, ориент прекрасно иллюстрирует треугольник CAP: при отсутствии сетевой связности вы можете иметь либо консистентную систему, пожертвовав доступностью и производительностью (пример с мастер-слейвом), либо HA/HL-систему, пожертвовав строгой консистентностью (пример с мульти-мастером и, желательно, кворумом меньше 100%)
vintage
Не уверен можно ли в Ориенте сделать так, чтобы слейв давал отлуп при потере синхронизации.
Как видите вы сами, гаворя о CAP, используете другие термины (консистентность, доступность, производительность). А то что мы не можем обеспечить синхронизацию, если между узлами нет связи, и как следствие вынуждены выбирать отказывать ли в обслуживании или выдавать устаревшие данные — это очевидно без всяких «теорем».
lair
Как же другие? Consistency, availability. Просто в CAP «производительность» заложена в «доступность», потому что доступность ограничена во времени.
vintage
Факт номер 2 в упомянутой мной выше статье как раз об этом :-)
lair
Тогда в чем ваши претензии к CAP? Она есть, и orientdb ее очередной раз подтверждает.
vintage
http://habrahabr.ru/post/267079/#comment_8581265
lair
Примеры в студию.
lair
Да, кстати, по поводу «тем больше точек отказа».
Когда у меня отказывает «шуруповерт-дрель-перфоратор» — я не могу ни заворачивать шурупы, ни сверлить, ни долбить стены. Когда у меня отказывает шуруповерт — я могу взять отвертку, а дырки делать дрелью. Когда отказывает перфоратор — заворачивать шурупы в уже пробитые дырки.
vintage
Достаточно иметь запасной шуруповёрт и когда отказывает один — делать дырки, заворачивать шурупы и долбить стены другим, не теряя возможности делать что-то из этих действий. При этом иметь взаимозаменяемые между ними детали.
lair
И вы что-то говорите о бездонном ящике для инструментов? Иметь по две (как минимум) копии каждого инструмента?
vintage
Не каждого, а одного универсального. А вот вам для обеспечения того же уровня надёжности придётся дублировать уже каждый специализированный инструмент.
lair
Не бывает совсем универсальных инструментов (вы не замените шуруповертом пилу).
И да, мне не нужен тот же уровень надежности, мне достаточно ситуации, когда при отказе одного инструмента не останавливается весь рабочий процесс.
vintage
Если у вас отказал перфоратор, то вы не сможете пробурить отверстие, чтобы завинтить в него шуруп отвёрткой.
lair
Как уже говорилось выше, у меня есть другие набуренные отверстия. Если нет — ну что ж, горе мне, сегодня я отдыхаю.
(ну или пойду полочки скручивать, для этого мне перфоратор не нужен)
lair
Угу. Моя несущая бетонная стена передает этим «шуруповертам» пламенный привет.
vintage
Вы пробовали или теоретизируете?
lair
Эти конкретные не пробовал (а что их пробовать, в них все равно бур на 25 не влезет), а вообще на моей стенке заткнулось три разных дрели (дрели! не шуруповерта).
lair
Собственно, даже в видео видно, с каким мучением они сверлят какой-то непонятный камень.
vintage
Бур на 25 и в перфоратор-то не в каждый влезет :-) Сочувствую вашему горю, ваши специфические условия требуют специфического инструмента. Именно поэтому я выделил жирным ремарку «когда в этом есть необходимость». Но если необходимость не продиктована особо прочными стенами, то не вижу смысла покупать кучу специализированных инструментов.
Да какие там мучения? Что лёгкий инструмент сильнее вибрирует? или что медленно сверлит? Не такая уж большая жертва за мобильность.
lair
Ура, вы наконец-то с этим согласились.
Медленно сверлит — видно, что не хватает мощности — на более прочной стене заткнется — даже на этой стене будет садиться аккумулятор чаще, чем надо — чем дольше работаешь, тем больше устаешь.
Я, знаете ли, очень ценю, что почти любая дырка в моей стене делается моим перфоратором за секунды.
vintage
А я с этим и не спорил. Не всем же так повезло как вам :-)
Если бы я каждый день делал дырочки — я бы наверно тоже это ценил. А вот раз в месяц — ничего страшного, если потребуется чуть больше времени.
lair
А мне и раз в месяц жалко свое время и силы.
robert_ayrapetyan
Ребята, вы, случайно, ремонтами не занимаетесь?
vintage
Я завязал…
potapuff
Пора завязывать на сегодня: сперва прочитал Postgres не стоит на месте