Комментарии 339
Наверное СУБД — это все же инструмент. И в зависимости от задачи мы берем тот или иной инструмент (это кстати и к голосованию относится)Это сферическое «правильное» утверждение в вакууме. На практике один хороший шуруповёрт легко заменяет десяток инструментов для разных задач (от миксера до перфоратора).
Универсальных СУБД не существует.Обоснуйте, пожалуйста :-)
Тем больше вам нужно инструментов для выполнения разных задач.
У меня в каждый конкретный момент задачи ограничены.
Тем больше точек отказа.
… и тем меньше опасность отказа каждой точки.
Только ящик с инструментами бездонный :-)
> … и тем меньше опасность отказа каждой точки.
Тем больше вероятность отказа хотя бы одной точки. Так и будете спорить с тем, что простые решения надёжней? :-)
Только ящик с инструментами бездонный :-)
Не вижу в этом ничего плохого. Особенно в случае с ПО.
Так и будете спорить с тем, что простые решения надёжней?
Понятие «надежности» нынче не так однозначно, как вам кажется. Какая система «надежнее» — та, которая падает с вероятностью 25%, но вся, или та, в которой с вероятностью 50% происходит потеря части функциональности?
Не вижу в этом ничего плохого. Особенно в случае с ПО.В случае ПО вы тратите время на интеркоммуникацию и поддержку разных инструментов.
Понятие «надежности» нынче не так однозначно, как вам кажется.Я понимаю, что попираю устои, но вы не могли бы вести себя менее спесиво? Спасибо.
Какая система «надежнее» — та, которая падает с вероятностью 25%, но вся, или та, в которой с вероятностью 50% происходит потеря части функциональности?Та, в которой не происходит при этом потеря данных и их согласованности :-)
В случае ПО вы тратите время на интеркоммуникацию и поддержку разных инструментов.
Вместо того, чтобы тратить его на попытки забить гвозди гантелей. Я считаю, это выигрыш.
Та, в которой не происходит при этом потеря данных и их согласованности
Для простоты — в обеих.
Вместо того, чтобы тратить его на попытки забить гвозди гантелей. Я считаю, это выигрыш.Вы забиваете даже шурупы (деревья, графы) молотком (РСУБД), а я вам предлагаю шуроповёрт (мультимодельную СУБД) и не пользоваться одноразовыми гвоздями (таблицами).
Для простоты — в обеих.В одной ACID СУБД потерь не будет. Но если вы будете использовать «на каждый чих свой инструмент», то без услуг СУБД без ACID явно не обойдётесь.
Вы забиваете даже шурупы (деревья, графы) молотком (РСУБД),
Вы не знаете, что, где и как я делаю.
а я вам предлагаю шуроповёрт (мультимодельную СУБД)
А эта ваша мультимодельная СУБД умеет реляционную модель?
Но если вы будете использовать «на каждый чих свой инструмент», то без услуг СУБД без ACID явно не обойдётесь.
(А вы все еще держитесь за ACID?)
Вопрос был не в этом, а в том, что есть две системы с разными вероятностями отказа (и последствиями этого отказа). Для простоты обсуждения ACID-гарантии у них одинаковые. Какая из них «надежнее»?
А эта ваша мультимодельная СУБД умеет реляционную модель?Джойны не умеет за не надобностью. Эквивалент таблицы из SQL — класс. orientdb.com/docs/last/Tutorial-Document-and-graph-model.html
А вы все еще держитесь за ACID?А чего б не держаться за хорошие вещи?
Вопрос был не в этом, а в том, что есть две системы с разными вероятностями отказа (и последствиями этого отказа). Для простоты обсуждения ACID-гарантии у них одинаковые. Какая из них «надежнее»?При прочих равных комбинация двух технологий не может быть надёжней одной. OrientDB, например, образует аналог RAID но для баз данных, так что отказ одного узла не фатален.
Джойны не умеет за не надобностью. Эквивалент таблицы из SQL — класс.
Она еще и индексные оптимизации не умеет (если я, конечно, ничего не путаю).
Та самая ситуация, когда вы мне предлагаете шуруповерт вместо перфоратора… а у меня несущая бетонная стена.
А чего б не держаться за хорошие вещи?
Стоимость реализации?
При прочих равных комбинация двух технологий не может быть надёжней одной.
А откуда вы взяли «комбинацию двух технологий»? Я, вроде бы, говорил о системе в целом.
Та самая ситуация, когда вы мне предлагаете шуруповерт вместо перфоратора… а у меня несущая бетонная стена.Нет нет, если у вас такая прочная стена, то вам стоит в дополнение к универсальному шуруповёрту приобрести перфоратор. А вот дрель можно и не покупать.
Стоимость реализации?Если стоимость данных меньше стоимости ACID, то да, можно и поиграть с ненадёжными инструментами :-) Но по мне так чем меньше непредсказуемости тем лучше, так что без веских аргументов я бы не стал отказываться от ACID.
А откуда вы взяли «комбинацию двух технологий»? Я, вроде бы, говорил о системе в целом.Система в целом состоит из разных задач. А к каждой вы предлагаете индивидуальный подход. Я же говорю, что есть инструменты, которые без лишнего оверхеда позволяют решать сразу несколько типов задач. Что в этом плохого — ума не приложу.
Индексные оптимизации — это вы о чём?
Вот об этом:
SELECT COUNT(*) FROM SomeData WHERE SomeField = 15
Работает себе из коробочки полным перебором таблицы. Стало медленно — построили индекс, и внезапно — не трогая кода! — стало быстрее в разы.
Если стоимость данных меньше стоимости ACID, то да, можно и поиграть с ненадёжными инструментами
Вы так говорите, словно кроме ACID надежных инструментов не бывает.
Я же говорю, что есть инструменты, которые без лишнего оверхеда позволяют решать сразу несколько типов задач.
Вот «без лишнего оверхеда» — еще надо доказать.
Но речь здесь шла не о том, а о простом вопросе «как меняется надежность системы с увеличением числа точек отказа». Я привел конкретный пример — вы до сих пор не можете ответить, что происходит с надежностью системы.
Работает себе из коробочки полным перебором таблицы. Стало медленно — построили индекс, и внезапно — не трогая кода! — стало быстрее в разы.
Ориент тоже поддерживает индексы разных типов: orientdb.com/docs/last/Indexes.html
Вы так говорите, словно кроме ACID надежных инструментов не бывает.ACID — это и есть различные аспекты надёжности, без которых данным полученным из БД нельзя доверять.
Я привел конкретный пример — вы до сих пор не можете ответить, что происходит с надежностью системы.Мы ходим по кругу. Мне нечего добавить к тому, что я уже сказал.
Ориент тоже поддерживает индексы разных типов: orientdb.com/docs/last/Indexes.html
Какой-то из них работает так, как описано в моем примере?
ACID — это и есть различные аспекты надёжности, без которых данным полученным из БД нельзя доверять.
Вот только ACID на распределенных системах на редкость дорог, и поэтому чаще не используется, чем используется. Но вы все равно пользуетесь этими системами (и доверяете им). И даже на не-распределенной БД можно жить без полноценного ACID. С ним, конечно, легче (пока вы не строите высоконагруженную систему), но и без него можно.
Он дорог лишь при большом числе реплик, но не шардов. Ориент позволяет гибко настроить как кластеры (наборы однотипных узлов данных) раскидываются по узлам (инстансам субд).
Разумеется.
Я так понимаю, это про индексы… вы, конечно же, можете показать, где в документации написано, что с момента построения индекса по полям все запросы по этим полям автоматически попадают в индекс?
Он дорог лишь при большом числе реплик, но не шардов.
Ровно наоборот. Количество реплик не влияет на стоимость ACID (если вы, конечно, не включаете в ACID write-quorum, которого там не было изначально). А вот каждый шард — это, потенциально, новая нода в распределенной транзакции.
(да, а еще бывают распределенные транзакции между несколькими экземплярами/системами)
Я так понимаю, это про индексы… вы, конечно же, можете показать, где в документации написано, что с момента построения индекса по полям все запросы по этим полям автоматически попадают в индекс?Интересно, почему вы сомневаетесь, что это так? :-) Индексы работают также как в любой РСУБД. Можете проверить это explain-ом.
Количество реплик не влияет на стоимость ACID (если вы, конечно, не включаете в ACID write-quorum, которого там не было изначально).Куда ж без него? Если кворум не будет достигнут, то транзакция не пройдёт, а мы уже отчитались, что прошла.
А вот каждый шард — это, потенциально, новая нода в распределенной транзакции.А реплика — гарантированная новая нода в распределённой транзакции.
(да, а еще бывают распределенные транзакции между несколькими экземплярами/системами)А мы сейчас о чём говорили?
Интересно, почему вы сомневаетесь, что это так?
Потому в документации написано, что обращение к индексу делается через префикс, и нигде не написано иного. Если это не так — прекрасно.
Куда ж без него? Если кворум не будет достигнут, то транзакция не пройдёт, а мы уже отчитались, что прошла.
Это если кворум на запись больше единицы.
А реплика — гарантированная новая нода в распределённой транзакции.
Только если вы используете стопроцентный кворум на запись.
А мы сейчас о чём говорили?
Об операциях внутри одной системы (потому что и реплики, и шардинг — это одна система).
Потому в документации написано, что обращение к индексу делается через префикс, и нигде не написано иного. Если это не так — прекрасно.Это просто дополнительный функционал. Узлы индексов — это те же узлы графа на низком уровне.
Это если кворум на запись больше единицы.Если кворум меньше большинства.
Об операциях внутри одной системы (потому что и реплики, и шардинг — это одна система).Имеются ввиду транзакции между разными СУБД? Ну, я про такие не слышал. Разве что через приложение.
Это просто дополнительный функционал. Узлы индексов — это те же узлы графа на низком уровне.
Это само по себе ни о чем не говорит и ничего не обещает.
Если кворум меньше большинства.
Эээ… вы как-то по-своему понимаете кворум. Write quorum — это число реплик, которые должны рапортовать, что запись прошла успешно, прежде чем она будет признаной успешной системой в целом. Большинство тут ни при чем. Соответственно, транзакция становится распределенной в тот момент, когда write quorum больше единицы.
Имеются ввиду транзакции между разными СУБД?
Между разными системами — СУБД не единственный транзакционный ресурс.
Ну, я про такие не слышал.
А зря. Они есть, и они составляют немалую головную боль.
Не слышал — в смысле реализаций такого в СУБД, а не вообще.
Не слышал — в смысле реализаций такого в СУБД, а не вообще.
В MS SQL есть, например. Другое дело, что все равно эта реализация рано или поздно упирается в ограничения (или принципиальную невозможность), и вы вынуждены делать систему, не имеющую ACID в одной из точек. После этого, внезапно, становится понятно, как работать с системами, которые имеют очень ограниченные ACID-гарантии.
В-третьих — CAP-«теорема».
Вот именно, что «теорема» :-)
Поэтому давайте напихаем побольше разных no-acid систем, чтобы «всё как у взрослых»?
Нет, поэтому давайте не будем ограничивать себя только теми архитектурами, которые дают ACID в границах системы.
Вот именно, что «теорема»
Опровергнуть ее тоже пока никому не удалось. Собственно, OrientDB ей удовлетворяет.
(http://habrahabr.ru/post/231703/)[Давайте не будем снова вспоминать эти глупости.] :-)
И всё же тем, что дают ACID стоит, отдать предпочтение.
Ну да, нам всем хочется жить в идеальном мире.
Давайте не будем снова вспоминать эти глупости
Ничего глупого в CAP нет. Она просто помогает правильным образом понимать некоторые компромисы.
В частности, как уже говорилось, Orient не поддерживает consistency в понимании CAP-теоремы, и при этом еще и отказывается от availability при сетевом отказе… так себе компромис, будем честными.
During the distributed transaction, in case of rollback, there could be an amount of time when the records appear changed before they are rollbacked.
Ну то есть, если не используются локи и master-slave конфигурация, то такая ситуация вполне возможна из-за конкурирующей транзакции.
Но, как видите, ориент прекрасно иллюстрирует треугольник CAP: при отсутствии сетевой связности вы можете иметь либо консистентную систему, пожертвовав доступностью и производительностью (пример с мастер-слейвом), либо HA/HL-систему, пожертвовав строгой консистентностью (пример с мульти-мастером и, желательно, кворумом меньше 100%)
Как видите вы сами, гаворя о CAP, используете другие термины (консистентность, доступность, производительность). А то что мы не можем обеспечить синхронизацию, если между узлами нет связи, и как следствие вынуждены выбирать отказывать ли в обслуживании или выдавать устаревшие данные — это очевидно без всяких «теорем».
Когда у меня отказывает «шуруповерт-дрель-перфоратор» — я не могу ни заворачивать шурупы, ни сверлить, ни долбить стены. Когда у меня отказывает шуруповерт — я могу взять отвертку, а дырки делать дрелью. Когда отказывает перфоратор — заворачивать шурупы в уже пробитые дырки.
Достаточно иметь запасной шуруповёрт и когда отказывает один — делать дырки, заворачивать шурупы и долбить стены другим, не теряя возможности делать что-то из этих действий.
И вы что-то говорите о бездонном ящике для инструментов? Иметь по две (как минимум) копии каждого инструмента?
И да, мне не нужен тот же уровень надежности, мне достаточно ситуации, когда при отказе одного инструмента не останавливается весь рабочий процесс.
Не бывает совсем универсальных инструментов (вы не замените шуруповертом пилу).Конечно, но и задачи-то в большинстве случаев типовые, а не «уникальные».
И да, мне не нужен тот же уровень надежности, мне достаточно ситуации, когда при отказе одного инструмента не останавливается весь рабочий процесс.Если у вас отказал перфоратор, то вы не сможете пробурить отверстие, чтобы завинтить в него шуруп отвёрткой.
Да какие там мучения? Что лёгкий инструмент сильнее вибрирует? или что медленно сверлит? Не такая уж большая жертва за мобильность.
Сочувствую вашему горю, ваши специфические условия требуют специфического инструмента.
Ура, вы наконец-то с этим согласились.
Да какие там мучения? [...] или что медленно сверлит?
Медленно сверлит — видно, что не хватает мощности — на более прочной стене заткнется — даже на этой стене будет садиться аккумулятор чаще, чем надо — чем дольше работаешь, тем больше устаешь.
Я, знаете ли, очень ценю, что почти любая дырка в моей стене делается моим перфоратором за секунды.
Если бы я каждый день делал дырочки — я бы наверно тоже это ценил. А вот раз в месяц — ничего страшного, если потребуется чуть больше времени.
Приведите Ваши реальные сравнения, что сколько весит и каково время выполнения запросов в каждом случае, только после этого можно о чем-то говорить всерьез.
У меня не стояла задача всесторонне исследовать производительность — просто показать, что оно как минимум не хуже и имеет смысл присмотреться.
Размер на диске:
PostgreSQL: 600mb
OrientDB: 750mb
Вывод: объемы сопоставимы.
Разница в 25% — это для вас «сопоставимы».
Замеры скорости, сделанные разными инструментами — тоже доставляют.
Ну и, наконец, тестируете вы на конкретной задаче, которая для графов выгодна.
Замеры скорости имеют фору у PostgreSQL ибо он напрямую общался с СУБД по бинарному протоколу, а не через JS прослойку в NodeJS.
Тестировал я на наиболее частом и сложном запросе. Вы бы не придирались :-) Если бы эти замеры доказывали неоспоримые преимущества OrientDB перед PostgreSQL по всем показателям на всех задачах, я бы пренепременно упомянул их в статье. Возьмите и проверьте на своих задачах и сделайте выводы. Сейчас же вы просто уверены, что «ничего не может быть быстрее моей любимой СУБД» и требуете от меня доказательств обратного.
25% — это во первых не такая уж большая разница.
Когда у вас размеры БД измеряются терабайтами, вы будете иначе к этому относиться.
А во вторых, там было много дубликатов связей из денормализованной SQL базы, которые графовую базу только раздували и замедляли. [...] Замеры скорости имеют фору у PostgreSQL ибо он напрямую общался с СУБД по бинарному протоколу, а не через JS прослойку в NodeJS.
Это означает, что ваше тестирование некорректно.
Тестировал я на наиболее частом и сложном запросе.
Наиболее частом и сложном для вашей системы. А в «моей» системе таких запросов нет, зато дофига объемных выборок с отбором, группировкой и агрегатами.
Сейчас же вы просто уверены, что «ничего не может быть быстрее моей любимой СУБД» и требуете от меня доказательств обратного.
Вот еще. Я точно знаю, что есть СУБД, которые быстрее тех СУБД, которыми я пользуюсь. Заодно я знаю, благодаря чему это происходит, и что я теряю, чтобы приобрести эту скорость.
Когда у вас размеры БД измеряются терабайтами, вы будете иначе к этому относиться.С чего бы? Плюс-минус террабайт в таких масштабах погоды не делают. А погоду делают совсем другие метрики. Возможности масштабирования, например.
Это означает, что ваше тестирование некорректно.Оно достаточно корректно для поставленной задачи.
Наиболее частом и сложном для вашей системы. А в «моей» системе таких запросов нет, зато дофига объемных выборок с отбором, группировкой и агрегатами.Разумеется. Вы же хотели конкретный пример — вы его получили. А теперь жалуетесь, что он имеет мало чего общего с вашими задачами.
Вот еще. Я точно знаю, что есть СУБД, которые быстрее тех СУБД, которыми я пользуюсь. Заодно я знаю, благодаря чему это происходит, и что я теряю, чтобы приобрести эту скорость.Ну раз вы всё знаете наперёд без тестирования, то мне нечего вам возразить :-)
тестируете вы на конкретной задаче, которая для графов выгодна
Так автор, как мне показалось, как раз стремится доказать, что таких «выгодных» — большинство.
Нонконформи́зм — стремление индивида придерживаться и отстаивать установки, мнения, результаты восприятия, поведение и так далее, прямо противоречащие тем, которые господствуют в данном обществе или группе. Часто считается синонимом понятия «негативизм» и антонимом понятия «конформизм». В некоторых случаях нонконформизмом называют просто готовность индивида отстаивать свою личную позицию в тех случаях, когда она противоречит позиции большинства. В таких случаях описанное в данной статье явление выделяют под названием «антиконформи́зм»
готовность индивида отстаивать свою личную позицию в тех случаях, когда она противоречит позиции большинстваи
человек, который не держится за свои привычки и всегда готов их поменять, если в том есть необходимостьсовсем не одно и тоже. Ваше опредление больше похоже на лабильность
Хорошую базу вы для продакшена выбрали. Главное, что не пришлось над дизайном и запросами к РСУБД думать.
Но альтернатив у OrientDB я особо не вижу. Возвращаться на реляционные — боже упаси. И не потому, что я не люблю думать о дизайне и запросах, а именно потому, что я люблю думать о дизайне. А дизайн реляционной базы — это всегда костыль на костыле и приходится решать проблемы, которых вообще быть не должно при правильном дизайне.
А дизайн реляционной базы — это всегда костыль на костыле
Серьезно? Всегда?
Вот организация учитывает находящиеся в ее собственности запасы нефти, газа и разных ценных металлов. Ее интересует — на каждый отчетный момент — общая стоимость запасов, а так же стоимость в разбивке по конкретному наименованию, виду, учетной категории и складу. И все то же самое — по объему и весу.
Как мы понимаем, для РСУБД это очень простая по дизайну задача. И я что-то не вижу там ни одного, как вы выражаетесь, костыля.
1. многие-ко-многим — костыли
2. деревья — костыли
3. большое разнообразие свойств — костыли
Без всего этого, ниша сужается до области OLAP, где опять же рулят не реляционные СУБД.
маленькой
Маленькой, серьезно?
многие-ко-многим — костыли
А почему вы считаете промежуточную таблицу костылем, кстати? Это всего лишь стандартный шаблон, вполне логично описывающий происходящее.
деревья — костыли
«Костыли» нужны, когда вы хотите иметь эффективные выборки по определенными видам деревьев. Это нужно не всегда. И, в общем-то, некоторые СУБД уже включают встроенную поддержку деревьев, так что тут тоже костыли пропали.
большое разнообразие свойств — костыли
Нет там никаких костылей.
ниша сужается до области OLAP, где опять же рулят не реляционные СУБД.
… а какие?
А почему вы считаете промежуточную таблицу костылем, кстати? Это всего лишь стандартный шаблон, вполне логично описывающий происходящее.Лишняя сущность, усложняющая работу, замедляющая выборки.
«Костыли» нужны, когда вы хотите иметь эффективные выборки по определенными видам деревьев.Было бы странно хотеть неэффективные выборки)
И, в общем-то, некоторые СУБД уже включают встроенную поддержку деревьев, так что тут тоже костыли пропали.Наличие встроенной поддержки костылей не делает их более эффективными. рекурсивные запросы не избавляют от сложности log(N) каждого хопа, где N — число записей в таблице. ordpath не избавляет от обновления кучи узлов при изменении дерева.
Нет там никаких костылей.
Да ну? И как же без костылей засунуть в РСУБД гетерогенные сущности?
… а какие?Тут я не специалист, но говорят колоночные рулят в этой области.
Лишняя сущность, усложняющая работу, замедляющая выборки.
У вас есть реальные тесты, подтверждающие замедление?
Было бы странно хотеть неэффективные выборки)
Иногда конкретный вид выборок никого не волнует (его просто нет в бизнес-кейсе).
Наличие встроенной поддержки костылей не делает их более эффективными. рекурсивные запросы не избавляют от сложности log(N) каждого хопа, где N — число записей в таблице. ordpath не избавляет от обновления кучи узлов при изменении дерева.
Понимаете ли, если для меня работа с деревом прозрачна, и скорость меня устраивает — чего еще мне хотеть?
Да ну? И как же без костылей засунуть в РСУБД гетерогенные сущности?
А в чем проблема?
У вас есть реальные тесты, подтверждающие замедление?Временная сложность алгоритмов для вас не достаточный аргумент? У каждого джойна она О(n*log(N)) при использовании индекса.
Иногда конкретный вид выборок никого не волнует (его просто нет в бизнес-кейсе).Мы опять скатились к ограничению области применимости РСУБД: «когда плевать на эффективность выборки» или «только для небольших иерархий».
А в чем проблема?В том, что в одной таблице могут быть лишь гомогенные сущности.
Временная сложность алгоритмов для вас не достаточный аргумент?
Нет. Когда мы начинаем говорить о конечной производительности, константы тоже имеют значение.
У каждого джойна она О(n*log(N)) при использовании индекса.
Только если стоимость прохода по индексу — O(log(N))
Мы опять скатились к ограничению области применимости РСУБД: «когда плевать на эффективность выборки»
Извините, но… нет. Сами по себе РСУБД дают очень эффективный механизм выборок.
В том, что в одной таблице могут быть лишь гомогенные сущности.
А внутри одного класса в ООП могут быть только объекты этого класса. И что?
Нет. Когда мы начинаем говорить о конечной производительности, константы тоже имеют значение.Есть основания полагать, что константы при прямых ссылках больше?
Только если стоимость прохода по индексу — O(log(N))А есть индексы с меньшей сложностью?
Извините, но… нет. Сами по себе РСУБД дают очень эффективный механизм выборок.Не более эффективный, чем в любой другой СУБД с поддержкой индексов. Алгоритмы одни и те же.
А внутри одного класса в ООП могут быть только объекты этого класса. И что?То, что в ООП есть полиморфизм. А в РСУБД всё гвоздями приколочено к таблицам. И один индекс на несколько таблиц не построить, и выборка из 100 таблиц требует полного перечисления их имён и связей между ними.
Есть основания полагать, что константы при прямых ссылках больше?
Есть основания полагать, что мы ничего о них не знаем. Равно как и о цене поддержки.
А есть индексы с меньшей сложностью?
Orient же утверждает, что сделал доступ O(1) к произвольному элементу БД. Значит, ничего не мешает сделать так же организованный доступ и в РСУБД.
Не более эффективный, чем в любой другой СУБД с поддержкой индексов. Алгоритмы одни и те же.
Это утверждение работает в любую сторону.
То, что в ООП есть полиморфизм.
… создающий кучу реализационных проблем регулярно.
И один индекс на несколько таблиц не построить
Построить. Но зачем?
и выборка из 100 таблиц требует полного перечисления их имён и связей между ними.
Плата за структуру.
Orient же утверждает, что сделал доступ O(1) к произвольному элементу БД. Значит, ничего не мешает сделать так же организованный доступ и в РСУБД.Архитектура мешает. Нужно не просто id в поле хранить, но и поддерживать такие значения как linkmap, linkset, linklist.
… создающий кучу реализационных проблем регулярно.Каких же?
Построить. Но зачем?Как? И что значит зачем? Чтобы делать выборку по одному индексу, а не по 100.
Плата за структуру.Полиморфизм позволяет не платить за структуру.
Нужно не просто id в поле хранить, но и поддерживать такие значения как linkmap, linkset, linklist.
Зачем? Если мы можем сделать O(1) доступ по ключу, то дальше стоимость выборки коллекции — O(n) даже в случае реализации с дополнительной таблицей.
Каких же?
Необходимость придерживаться LSP, например. Про проблему квадрата и прямоугольника слышали?
Полиморфизм позволяет не платить за структуру.
Спорный тезис. Насколько я помню, сама по себе поддержка наследования в языке приводит к (некоторым) потерям производительности.
К полиморфизму проблемы наследования относятся очень опосредованно.
Во первых мы про СУБД, а не про ЯП говорим. А во вторых, не все языки одинаково бесполезны.
O(1) по ключу мы можем добиться лишь потратив O(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
Передал, говорит у него там O(n) по памяти, где n — число связей с заданным именем в заданном узле. И эта сложность не зависит от общего числа узлов в графе. В отличие от индексов.
Индексы здесь вообще ни при чем — они для данной задачи не нужны, весь доступ осуществляется по основному ключу (я под индексом понимаю вторичный индекс). Так что я не очень понимаю, почему, если считать, что O(1) по ключу — достижимы, то нельзя сделать выборку коллекции за O(n), не используя никаких дополнительных типов.
Полиморфизм примерно в этом:
Вы правда не знаете, как это реализуется в реляционных СУБД? Я знаю три традиционных способа, дающих разные преимущества (и больше одного ОРМ, который сделает это незаметно для меня).
Вообще, конечно, выглядит красиво, ничего не скажешь. Но вопрос производительности остается неочевидным.
Я даже 4 способа знаю разной степени костыльности :-)
А во-вторых, повторю вопрос: если предположить, что используется доступ по ключу с константной стоимостью (т.е. то, что утверждается в ориенте), что мешает организовать проход по коллекции за линейное время (от объема коллекции)?
И вот пока я думал эту мысль, до меня внезапно дошла простая вещь, которую я почему-то пропустил раньше. Помните вот этот диалог?
Только если стоимость прохода по индексу — O(log(N))
А есть индексы с меньшей сложностью?
Так вот, индексы с меньшей сложностью есть. У хэш-таблицы амортизированная сложность доступа — O(1).
Чтобы хеш таблица работала за O(1) необходим непрерывный участок памяти объёмом O(N).
Не обязательно памяти. Любого хранилища.
Кроме того, хеш таблицы очень дорого перестраивать для поддержки больших объёмов данных.
А вот это вопрос констант как раз, который вы раньше проигнорировали.
Не игнорировал. И тут дело не в константах, а именно в алгоритмической сложности ресайза. Бинарные деревья куда лучше приспособлены для больших объёмов.
Я говорил не только про оперативную память.
Осталось выяснить, каким же же чудом Ориент обходит эти ограничения.
И тут дело не в константах, а именно в алгоритмической сложности ресайза.
Еще раз: амортизированная алгоритмическая сложность хэш-таблицы — O(1), как на чтение, так и на добавление. Ресайз сюда включен.
Ну да, обычно всё летает, а иногда встаёт колом на час.
Никак не обходит.
Прекрасно, значит, и здесь у него (ориента) нет никаких концептуальных преимуществ.
Ну да, обычно всё летает, а иногда встаёт колом на час.
Scheduled maintenance рулит. Иначе вы на банальном приросте файла под БД можете очень больно лечь.
Прекрасно, значит, и здесь у него (ориента) нет никаких концептуальных преимуществ.Есть. И я не буду больше повторять про ссылки.
Scheduled maintenance рулит. Иначе вы на банальном приросте файла под БД можете очень больно лечь.По вашему увеличение файла происходит путём копирования содержимого из маленькой непрерывной области в большую? :-)
Бинарные деревья куда лучше приспособлены для больших объёмов.
B-tree != бинарные деревья
Но отчеты очень удобно строить по реляционной БД
Не очень удобно. Даже если забыть про избыточность собственно SQL-запроса (разработчик вынужден хранить в голове связи типа contract.id = contract_transaction.contract_id и указывать их в запросе явно, хотя до этого указывал СУБД, что contract_transaction.contract_id не может указывать может указывать только на contract.id, не забывать включать таблицу в FROM, если указал её в SELECT или WHERE), то многие часто встречающиеся для отчётов задачи решаются средствами SQL нетривиально. Например, отчёт по балансу какого-то числового агрегатного поля сущности по дням, где должен быть указан баланс на начало дня, начисления за день, списания за день, баланс на конец дня, причём баланс на начало дня должен быть ноль, даже если сущность ещё не существует, отчёт должен быть по каждой дате, даже если транзакций по сущности не было, а если транзакций не было, то начисления и списания тоже должны быть нулями. А в наличии у нас сущность и
транзакции по ней. Как минимум, придётся извращаться с преобразованием NULL в 0 и установлением начального баланса в 0.
Как минимум, придётся извращаться с преобразованием NULL в 0
Вот поэтому изначально в реляционной теории NULL и не было. Соответственно, как только вы решаете проблему с преобразованием «нет данных» в нули (а это чистое бизнес-требование), ваша задачка решается легко и просто.
Впрочем, я с удовольствием послушаю про СУБД, в которой это строить проще.
А я не говорил, что они есть я спорил с утверждением, что в SQL строить подобные отчёты, довольно обычные в практике, удобно. Имхо, реляционная модель вообще (а её реализация в SQL особенно) слабо приспособлена для реализации, с одной стороны, отношений типа «имеет», «содержит», «принадлежит» и т. п. между сущностями и, с другой, для агрегирующих выборок с известным начальным состоянием.
Проще это делается в, например, документо-ориентированных СУБД, в которых в качестве языка запросов используется, например, javascript — обычный reduce на коллекцию с начальным состоянием. Другое дело, что цена этой простоты меня лично не устроила и мучаюсь с Postgre- и, пока, MySql. Ещё активно навязывают (поставщики внешних решений MS SQL через начальство), но пока сопротивляюсь.
Но вот start_balance + SUM(tr.amount) (где tr.amount NULL как отсутствующая в результате LEFT JOIN)
Просто нужно вытаскивать все агрегаты отдельно, тогда можно будет разделять «транзакций за день не было» и «общий баланс транзакций за день — 0». И складывать на уровне интерфейса, благо, это просто.
(на уровне SQL тоже не сложно, прямо скажем).
Проще это делается в, например, документо-ориентированных СУБД, в которых в качестве языка запросов используется, например, javascript — обычный reduce на коллекцию с начальным состоянием.
Описываемая вами простота приходит не от документо-ориентированности — а от использования JS. Сама модель никак на это не влияет.
Я люблю лес.
По лесу машины передвигаются плохо, а велосипеды хорошо.
Вывод: Считаю надо выкинуть все автомашины и всем пересесть на велосипеды.
Многие SQL-профи тут обычно заявляют, мол деревья и тем более графы в предметных областях почти не встречаются. Но стоит немного выйти из зоны комфорта как тут же увидишь, что любая предметная область на самом деле представляет из себя граф — набор сущностей, между которыми есть разнообразные отношения.
Это утверждение неверно. Любую предметную область можно представить в виде графа, однако это не означает, что это представление для нее наиболее эффективно. И тем более не значит, что это представление нужно выбирать для реализации.
Собственно, все же уже сказано в хорошей книжке.
Однако большинство предметных областей на граф ложатся лучше, чем на таблицы.
Что вы понимаете под «лучше»? Ну и в любом случае мне, конечно, интересно увидеть статистику, на основании которой вы делаете это утверждение.
(отдельно, конечно, неплохо бы определиться, что же вы именно понимаете под графами...)
Бизнес модель — коллекция сущностей с отношениями.
Графовая модель — коллекция узлов со связями.
Реляционная модель — таблицы с данными и всё.
Первая на вторую мапится 1-в-1. На третюю не памятся, ибо нет отношений (они указываются только потом, в запросе), да и сущности по сложнее кортежа примитивов.
Реляционная модель — таблицы с данными и всё.
На самом деле, нет. Реляционная модель — это таблицы с данными и их связи.
Первая на вторую мапится 1-в-1.
А еще бизнес-модель точно так же «точно» маппится на документо-ориентированную парадигму (потому что там тоже коллекция сущностей со связями) и на объектно-ориентированную парадигму.
Это все еще не значит, что любое из перечисленных представлений (включая реляционное) по каким-то причинам лучше подходит для реализации всех задач.
В таблицах нету связей. Там есть одинаковые числа в разных колонках разных таблиц. Смысл связей они обретают лишь при запросе и соответствующие записи могут быть найдены лишь по индексам.
Документная модель со связями — это уже графовая модель. Типа той, что мы видим в Ориенте.
В таблицах нету связей.
Это экзистенциальный вопрос. В таблице есть информация, позволяющая однозначно определить связанный объект. Этого достаточно.
Документная модель со связями — это уже графовая модель.
Тогда и табличная модель со связями — графовая модель, после чего вообще сравнивать нечего становится.
но физически нет ссылок на другие записи. Есть только числа по которым можно найти связанную запись только через поисковой индекс.
Вы так говорите, будто в других БД «физически» хранятся не «числа» (опустим для простоты тот факт, что идентификатором записи может быть что угодно). Те же самые числа, пусть даже в OrientDB они являются указателями на конкретное физическое место в БД.
Семантику этих «чисел» обеспечивают метаданные, лежащие поверх, и ограничивающие операции. Сейчас, наверное, все РСУБД поддерживают внешние ключи, как для ограничения множества допустимых значений, так и для распространения изменений. Семантически это эквивалентно ссылкам на объекты.
Вы можете к возрасту приджойнить айдишники и получить странный результат. А РСУБД ничего на это даже не возразит.
Да, могу — ни одна известная мне РСУБД не имеет ограничений на объекты под джойнами. Но есть и оборотная сторона — я могу приджойнить возраст к возрасту, или имя к имени, или результат группировки к результату группировки. Можно ли так сделать в графовой БД?
Можно, через подзапросы.
Можно, через подзапросы.
Во-первых, являются ли «подзапросы» свойством любой графовой БД?
Во-вторых, какова их функциональность и эффективность по сравнению с РСУБД?
2. Да такая же при наличии индексов. Разве что для full outer join нужно шаманить.
Я не говорю про любую ГСУБД. Но в любой толковой — можно. Из толковых я знаю только одну.
Значит, это не врожденное свойство графовых БД.
Да такая же при наличии индексов. Разве что для full outer join нужно шаманить.
Правда?
У меня есть две таблицы (два класса в терминах ориента), «книги» и «фильмы». В каждой из них есть поле «год». Мне нужно получить таблицу вида «год выхода — число книг — число фильмов». Считаем, что с каждой стороны есть хотя бы по одной записи для каждого года, поэтому достаточно
INNER JOIN
.Если честно, лень шаманить с селектами… в ГСУБД эта задача решается несколько иначе и более эффективно:
select value , book.length() as booksCount , movies.lengh() as moviesCount from Year
При этом это ограничение «с каждой стороны есть хотя бы по одной записи для каждого года» не требуется.
Во-вторых, увеличивается стоимость поддержки — когда у меня появляется новая сущность (диск, например), в котором я сделаю связь с годом, ориент сам добавит «ответное» свойство со стороны года, или его будет нужно добавлять руками?
В-третьих, это как раз типичный костыль: графовая модель не справляется с задачей, которая для реляционной модели проста, и вы вынуждены изменять семантику модели так, чтобы она влезла в граф.
В конце концов это приведет к тому, что у вас все свойства будут ребрами (со всеми вытекающими отсюда проблемами), вы получите «чистый» граф и модель категорий по Партриджу (которую на хабре уже обсуждали).
2. Если используется графовое апи, то обратные связи создаются автоматически. Если же документное (которое я нахожу более практичным), то ответное нужно создавать руками.
3. Я бы не назвал это таким уж прям костылём. Если у нас выводится аналитика по годам, то без сущности «год выпуска» так или иначе не обойтись. К ней надо будет привязывать не только вышедшие произведения, но и ежегодные премии, аналитические статьи и тп. А не вытягивать их по косвенным данным (датам во всех этих сущностях) при каждом запросе, внимательно следя, чтобы диапазоны не пересекались. Тем более что премия за текущий год может вручаться в следующем. А аналитическая статья за любой год может выйти хоть через десятилетие.
4. Можно ссылку, где обсуждали?
Это в РСУБД переход по связи дорогой. Тут же это почти ничего не стоит (прочитать лишний блок памяти, который, к тому же, скорее всего возьмётся из кэша).
Это все равно дополнительная операция. А кэши — они во всех СУБД есть.
Если же документное (которое я нахожу более практичным), то ответное нужно создавать руками.
Вот и увеличение стоимости поддержки.
Если у нас выводится аналитика по годам, то без сущности «год выпуска» так или иначе не обойтись.
Год выпуска — это не сущность, а атрибут.
К ней надо будет привязывать не только вышедшие произведения, но и ежегодные премии, аналитические статьи и тп. А не вытягивать их по косвенным данным (датам во всех этих сущностях) при каждом запросе, внимательно следя, чтобы диапазоны не пересекались. Тем более что премия за текущий год может вручаться в следующем. А аналитическая статья за любой год может выйти хоть через десятилетие.
Все эти проблемы решаются введением соответствующего атрибута, сущность все еще не нужна.
Можно ссылку, где обсуждали?
habrahabr.ru/post/246313
habrahabr.ru/post/245241
И вообще в комментариях почти к любому поcту maxstroy
Это все равно дополнительная операция.Она как минимум лучше масштабируется, чем джойны таблиц.
Вот и увеличение стоимости поддержки.Один раз пишется обобщённый код и всё. Ну то есть я реализовал своё графовое апи с поддержкой как двусторонних так и односторонних связей. То, что есть в Ориенте — всегда двустороннее и направленное
Год выпуска — это не сущность, а атрибут.Ссылка на сущность хранится в атрибуте. Это философский спор :-) Я лично усматриваю в годе выпуска все признаки сущности. Сформулировать их пока не возьмусь, чисто интуитивно.
Все эти проблемы решаются введением соответствующего атрибута, сущность все еще не нужна.Но с ней в целом удобней.
habrahabr.ru/post/246313Спасибо, почитаю.
habrahabr.ru/post/245241
Она как минимум лучше масштабируется, чем джойны таблиц.
Почему?
Один раз пишется обобщённый код и всё.
А создает описание связей в БД тоже «обобщенный код»?
Я лично усматриваю в годе выпуска все признаки сущности.
Попробуйте сформулировать, и поймете, что по этим признакам всё — сущность. Это, конечно, нативный для графа подход (все есть вершина кроме того, что ребро), но вы уверены, что вам будет удобно так работать.
Но с ней в целом удобней.
Удобнее вам реализовывать на графовой БД. Но в бизнесе этого нет… и что вы там говорили про то, что предметная область лучше ложится на граф?
Почему?Потому что скорость перехода по ссылке не зависит от числа записей в таблице…
А создает описание связей в БД тоже «обобщенный код»?Вполне, почему бы и нет?
вы уверены, что вам будет удобно так работать.Да, весьма.
Удобнее вам реализовывать на графовой БД. Но в бизнесе этого нет… и что вы там говорили про то, что предметная область лучше ложится на граф?В бизнесе есть «отчётные периоды» и это вполне себе бизнес сущности. И с ней удобнее и быстрее работать как с отдельной сущностью, а не жонглировать временными метками.
Потому что скорость перехода по ссылке не зависит от числа записей в таблице…
Уже проходили: для реляционной БД это тоже возможно.
Вполне, почему бы и нет?
Ну так, представляю себе результаты его работы.
Да, весьма.
Пробовали? Пока все ваши примеры — они документо-ориентированы.
В бизнесе есть «отчётные периоды» и это вполне себе бизнес сущности.
Не надо путать отчетные периоды и год выхода. Это очень разные вещи. А временные метки вы себе вообще сам придумали, я про них не слова не сказал.
Уже проходили: для реляционной БД это тоже возможно.Если б всё было так легко, никто бы не пилил NoSQL решения.
Ну так, представляю себе результаты его работы.Озвучите?
Пробовали? Пока все ваши примеры — они документо-ориентированы.Бизнес вообще документно ориентирован.
Не надо путать отчетные периоды и год выхода.Вы строите отчёты по годам. Вполне себе отчётные периоды.
Если б всё было так легко, никто бы не пилил NoSQL решения.
А вы думаете, NoSQL решения «пилят» из-за невозможности сделать константное время доступа по ключу?
Озвучите?
Если вкратце, то:
book.Editor_Person
.Бизнес вообще документно ориентирован.
Ну и как же вы собираетесь его положить на чистый граф тогда?
Вы строите отчёты по годам. Вполне себе отчётные периоды.
Нет, я строю отчеты по атрибуту «год выхода». Это не то же самое, что «отчетный период — 2010 год» или «финансовый год 2010».
А вы думаете, NoSQL решения «пилят» из-за невозможности сделать константное время доступа по ключу?Из-за фундаментальных проблем масштабирования РСУБД.
Если вкратце, то: book.Editor_Person.Что это?
Ну и как же вы собираетесь его положить на чистый граф тогда?Бизнес документы тоже имеют перекрёстные ссылки.
Нет, я строю отчеты по атрибуту «год выхода». Это не то же самое, что «отчетный период — 2010 год» или «финансовый год 2010».Не вижу разницы.
Как интересно! А расскажите какие там есть проблемы? И да кстати посмотрите про то как PostgreSQL ускоряют при помощи GPGPU.
Что это?
Это типичный пример именования, вышедшего из под обобщенного кода.
Бизнес документы тоже имеют перекрёстные ссылки.
Перекрестные ссылки — это, конечно, граф, но бизнес-документы — это не чистый граф, а речь выше шла именно об этом.
Не вижу разницы.
Я, в принципе, уже заметил.
Окей, представьте, что у вас не год, а дата — и вам надо строить аналитику по датам (рождения, смерти, свадьбы и развода).
Это типичный пример именования, вышедшего из под обобщенного кода.Зачем тип указывать в имени свойства?
Перекрестные ссылки — это, конечно, граф, но бизнес-документы — это не чистый граф, а речь выше шла именно об этом.Что такое «грязный граф»?
Окей, представьте, что у вас не год, а дата — и вам надо строить аналитику по датам (рождения, смерти, свадьбы и развода).Точно так же, создаём отдельные узлы для дат и имеем быструю аналитику по ним. Говорю же, принципы работы с графами несколько отличаются от подходов к которым вы привыкли при работе с таблицами.
Зачем тип указывать в имени свойства?
Потому что обобщенный код так сгенерил.
Что такое «грязный граф»?
Граф, в котором у вершин есть свойства.
Точно так же, создаём отдельные узлы для дат и имеем быструю аналитику по ним.
Вы себе представляете количество таких вершин?
Говорю же, принципы работы с графами несколько отличаются от подходов к которым вы привыкли при работе с таблицами.
Спасибо, я в курсе. Только почему-то подходы, применяемые в реляционной модели, вы считаете костылями, а подходы, применяемые в графовой — нет.
Потому что обобщенный код так сгенерил.Напишите нормальный обобщённый код :-)
Граф, в котором у вершин есть свойства.Теория графов не накладывает никаких ограничений на вершины.
Вы себе представляете количество таких вершин?Не больше чем узлов в индексе.
Спасибо, я в курсе. Только почему-то подходы, применяемые в реляционной модели, вы считаете костылями, а подходы, применяемые в графовой — нет.Потому что они имеют большую алгоритмическую сложность и меньшую наглядность.
Напишите нормальный обобщённый код
Если бы можно было написать нормальный обобщенный код, порождающий модель, соответствующую домену, программистов можно было бы выкинуть на свалку.
Теория графов не накладывает никаких ограничений на вершины.
И как следствие никак не описывает алгоритмы для работы с «дополнительными» данными.
Не больше чем узлов в индексе.
Вот только узлы в индексе я — как разработчик — не вижу. А вершины в граф добавлять мне.
Потому что они имеют большую алгоритмическую сложность
Докажите.
меньшую наглядность.
А это субъективно.
Если бы можно было написать нормальный обобщенный код, порождающий модель, соответствующую домену, программистов можно было бы выкинуть на свалку.Вы улетели в стратосферу. Что мешает генерировать нормальные имена в духе «book.editor»?
И как следствие никак не описывает алгоритмы для работы с «дополнительными» данными.А должна? К чему вы клоните?
Вот только узлы в индексе я — как разработчик — не вижу. А вершины в граф добавлять мне.Вы их фактически создаёте налету в агрегирующем запросе. Из таблиц «инфа о книгах» и «инфа о фильмах» создаёте виртуальную таблицу «инфа о годе выпуска».
Бизнес вообще документно ориентирован.
Бизнес обычно не документно ориентирован, документы, как правило, лишь средства отражения (учёта) состояния бизнес-процессов, модель по сути, по которой кто-то может узнать состояние бизнес-процессов на определенный момент времени (при условии, что документы составлялись в нужном объёме и фиксировали объективные состояния процессов).
Что мешает генерировать нормальные имена в духе «book.editor»?
Каждый раз что-нибудь новое.
А должна? К чему вы клоните?
К тому, что умение работать с документо-ориентированными данными для графа не свойственно.
Вы их фактически создаёте налету в агрегирующем запросе. Из таблиц «инфа о книгах» и «инфа о фильмах» создаёте виртуальную таблицу «инфа о годе выпуска».
Именно что виртуальную. Это сущность, которая появляется тогда, когда она нужна в отчете.
К тому, что умение работать с документо-ориентированными данными для графа не свойственно.Что такое «документно-ориентированные данные» и каким образом модель данных «граф» может работать?
Именно что виртуальную. Это сущность, которая появляется тогда, когда она нужна в отчете.И что хорошего в том, чтобы создавать её при каждом запросе отчёта?
Что такое «документно-ориентированные данные»
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.
каким образом модель данных «граф» может работать?
У каждой модели данных есть свои типовые операции, для которых она выгодна, набор операций, который на ней делать чрезвычайно неоптимально, и «всё остальное».
И что хорошего в том, чтобы создавать её при каждом запросе отчёта?
Отсутствие дублирования данных, например. Ну и вообще семантическая стройность.
Сформулировать их пока не возьмусь, чисто интуитивно.
Какой-то конкретный год — объективно существующая сущность, период реального физического времени между двумя (пускай и субъективно выбранными) событиями. Год издания книги — это отношение сущности «книга» к сущности «год» по признаку того, что событие «издание» произошло в данный конкретный период времени. Это не свойство книги, не её наполнение, это её отношение к внешнему миру, такое же, как, например, «страна издания».
(а) «книга» относится к классу «500 страниц»
(б) «книга» содержит 500 связей со страницами
Семантику этих «чисел» обеспечивают метаданные, лежащие поверх, и ограничивающие операции. Сейчас, наверное, все РСУБД поддерживают внешние ключи, как для ограничения множества допустимых значений, так и для распространения изменений. Семантически это эквивалентно ссылкам на объекты.
В том-то и дело, что не эквивалентно. Ограничения на значения и распространение изменений семантически означают именно ограничения и распространение, а при каждом запросе приходится указывать СУБД как две таблицы связывать, иначе в результат запроса попадёт результат их умножения, а не соединения, хотя в подавляющем большинстве случаев разработчики баз данных имеют в виду использование нескольких таблиц в одном выражении FROM исключительно для соединения исключительно по одной, заранее известной паре столбцов паре столбцов и даже косвенно сообщают эту информацию СУБД в виде ограничений, индексов и т. п., но СУБД их в целом игнорирует, воспринимая их только как прямые указания на создание ограничений и т. д., не понимая что, разработчик собирается эти таблицы использовать совместно исключительно соединив их по полям на которым наложены ограничения и, соответственно, не применяя оптимизаций (разве что на уровне кэшей), производя объединение при каждом запросе.
а при каждом запросе приходится указывать СУБД как две таблицы связывать, иначе в результат запроса попадёт результат их умножения, а не соединения, хотя в подавляющем большинстве случаев разработчики баз данных имеют в виду использование нескольких таблиц в одном выражении FROM исключительно для соединения исключительно по одной, заранее известной паре столбцов паре столбцов
Это ограничение не парадигмы, а языка запросов. Ничего не мешает написать иной язык запросов, который будет использовать существующие метаданные для получения желаемого эффекта. А SQL просто очень консервативен.
А с другой стороны… я правильно понимаю, что вы хотите чего-то навроде «есть таблицы Books и Authors, я хочу, чтобы когда я пишу
SELECT * FROM Books, Authors
, система автоматически строила джойн»? Или чего-то другого?В идеале вообще что-то вроде: SELECT Books.Title, Books.Authors.Name; добавляя нынешние FROM и JOIN лишь в случае необходимости изменения основного поведения.
В идеале вообще что-то вроде: SELECT Books.Title, Books.Authors.Name; добавляя нынешние FROM и JOIN лишь в случае необходимости изменения основного поведения.
Угу. Как ни странно, добрая половина ORM дает вам именно такое поведение, все еще имея внутри реляционный код. И для этого используются тривиальные метаданные. Причем, что характерно, O и M из ORM для этого не нужны, достаточно метаданных и конструктора запросов.
В DB/2, кстати, весьма зачетный внутренний язык был.
http://www.psychologos.ru/articles/view/piraha
SELECT title , authors.name , authors.muses.name FROM Book
Вернёт записи вида:
( "Hello" , [ "John" , "Artur" ] , [ [] , [ "Elena" ] ] ] )
Программирую я давно — с самой школы. Так как начинал что-то писать более-менее серьезное в Delphi, то понятия ООП «впитал с малолетства». А так как задачки были ерундовые, с СУБД тогда дела не имел.
Поиметь дело с ними пришлось несколько лет назад, когда тяжелая судьба занесла меня в Java Enterprise. Зная неплохо Java (а до нее мея опыт в C# и C++), я впервые столкнуля с тем, что такое реляционная база данных. А еще что такое ORM Hibernate. Влетел, можно сказать, обеими ногами и увяз по колено.
И вот, что я могу сказать о своих первых впечатлениях (которые потом, по мере использования, только укрепились).
Я полностью согласен с автором этого поста в вопросах критики по отношению к РСУБД. Представление объектов и связей между ними таблицами — совершенно немыслимый костыль, который явно пришел в индустрию из тех времен, когда ООП было только в голове (в лучшем случае — на бумаге), но не в коде. Потому что идеальной (по моим представлениям) системой является такая, при которой данные, с которыми работает ПО, зеркалируются в долговременное хранилище незаметно для разработчика. И тут, явно, никакая дополнительная конвертация (тем более, интеллектуальная и требующая дополнительного проектирования) недопустима.
Долгое время я мирился с когнитивным диссонансом, выслушивая со стороны старших товарищей аргументы в духе «таблицы проще хранить, с ними быстрее работать» и т. д… Я просто пожимал плечами и верил, что они правы. А сейчас вижу, что и этот оплот разваливается (если верить статье). Надо попробовать попользоваться хоть немного этой самой OrientDB при случае. Жаль, что теперешняя моя работа от СУБД далека диаметрально.
Пять-десять-пятнадцать лет назад доля таких задач была меньше
В том-то и дело, что я такими задачами почти не занимался. Мне было интересно «использовать ООП наполную катушку».
Я прекрасно понимаю, что для задач типа складских «сводная таблица цена-количество-стоимость» табличное представление — самое верное и простое. Понятно, что таблицы хороши для представления однородных данных…
Но эти задачи давно уже все решены. Сейчас действительно актуальны Wiki и соцсети. Как то, так и другое редставляется жутко нерациональным, если организовывать данные в виде таблиц. Как составить графовую модель сети Facebook, я, думаю, с точностью незначительных нюансов, нарисую за полчаса. А вот как эти данные уложить в табицы… Тут без поллитры точно не разберешься. А если редставить себе, что будет использоваться еще и ORM, то вообще кирдык психике (видел я сложность Hibernate-овских запросов на сравнительно примитивной задаче).
Мне кажется, что основная причина, по которой все до сих пор держатся за реляционщину — страх перед ошибками. Вот если мне скажут «мы используем Oracle, потому что его 20 лет писали и чинили, а твою <вставьте слово> я впервые вижу», то я это вполне пойму. А +25% к размеру базы — это не цена за простую понятную и легко масштабируемую программу, как мне кажется.
В том-то и дело, что я такими задачами почти не занимался. Мне было интересно «использовать ООП наполную катушку».
Понимаете, это заведомо неправильный подход. «Интересно» — решать конкретную прикладную задачу, выбрав для нее тот инструмент, который для нее подходит. Это не всегда ООП, это не всегда РСУБД, это не всегда <что угодно другое>.
Я вот сейчас для себя пилю проектик, в котором три года назад использовал бы РСУБД (MS SQL), год назад — документо-ориентированную БД (RavenDB), а сейчас, в итоге, взял хранилище событий (EventStore), а по мере увеличения нагрузки планирую добавлять read models на том, на чем будет оправданнее.
Я прекрасно понимаю, что для задач типа складских «сводная таблица цена-количество-стоимость» табличное представление — самое верное и простое. Понятно, что таблицы хороши для представления однородных данных… Но эти задачи давно уже все решены.
О нет. Выработана общая стратегия решения таких задач, но сами задачи далеко не решены, иначе бы рынок ПО резко схлопнулся. Компаний (например), автоматизирующих свой складской учет — все больше, и больше, и всем им нужно ставить ПО, и у некоторых из них — нетиповые задачи.
Мне кажется, что основная причина, по которой все до сих пор держатся за реляционщину — страх перед ошибками.
Основная причина — это непонимание, как работают «новые» (на самом деле, нет) БД, нежелание разбираться, и нежелание искать выгодные стороны (я, конечно, говорю о новых проектах, с унаследованным ПО все веселее). Но я вот знаю одну (весьма авангардную) разработческую компанию, которая между мажорными версиями своего ПО сменила используемую СУБД с RavenDB (документо-ориентированная) на MS SQL (РСУБД) — просто потому, что их не удовлетворял опыт работы с Raven.
Как составить графовую модель сети Facebook, я, думаю, с точностью незначительных нюансов, нарисую за полчаса.
Кстати, у ФБ — мультипарадигменная модель, там есть и графы, и документо-ориентированные куски. И это если не учитывать внутреннюю кухню, которую мы не видим.
Я, естественно, о бизнесе, а не о том, что они реализовали.
Добавлю, что в текущей момент работаю с обычной двузвенкой (клинет-сервер), но сущьности использую только на стороне клиентской программы (программы управления роботизированным комплексом). Это и обеспечивает более логичный с точки зрения ООП код, при этом не возникает определенных сложностей и затыков разобраться в миграции данных и понять причину того или другого поведения комплекса.
Тоже можно сказать, что это часный случай. Но в том то все и дело, что любое применение того или иного инструмента является частным случает — в примере от ТС часный случай использования шуруповерта в качестве отбойника.
В моей реализации бизнес сущности везде — и на клиенте, и на сервере, и в базе данных. И это, скажу я вам, крайне удобно и не слабо повышает эффективность трудозатрат. К тому же ещё сервер и клиент работают через один и тот же полиморфный js-api:
// передать управление салоном пользователю с id "cool-manager"
salon.Manager().set( [ 'cool-manager' ] , [ myPerson ] ).then( managers => {
console.log( managers.map( String )
} )
Так в чем же выигрыш?
Перевод в js-api для меня не делает погоды. Есть только один единственный модуль, который знаком с этой технологией — для обмена данных от внешнего клиента, чтоб переколбасить эти все данные во внутрениий, опримизированный и построеный для системы api и сформировать правильное сообщение в систему. Все. И то, если у клиентов совершенно другая система обмена сообщений (напрмер описанная на хабре HL7), то и этот модулек не будет использоваться.
Так подведем маленький итог нашей дискуссии: Сущности важны в основном процессе. Если у вас обработка(бизнес-логика) крутится непосретственно в базе — то тогда есть удобство использовать сущности. Иначе, любые конечные ветви взаимодествия извне полюбому упирается в плоскую передачу упорядоченных байтов, будь то обмен даххы наприме по tcp, хранение в бинарном файле или в РСУБД.
Все-то, конечно всё понимают, да только получается как в известном анекдоте: https://hsto.org/files/8bb/23b/a3a/8bb23ba3aede496395ac3a63d42380f2.jpg
Зная неплохо Java (а до нее мея опыт в C# и C++), я впервые столкнуля с тем, что такое реляционная база данных. А еще что такое ORM Hibernate. Влетел, можно сказать, обеими ногами и увяз по колено.
Прежде чем лезть в такое изучите теорию и практику РСУБД. То что ORM текущая абстракция не знает только очень ленивый человек.
Я не вполне согласен. У нас лишают возможности писать не за альтернативное мнение, а за отсутствие пиетета к авторитету большинства. То есть мнение-то каждый может иметь какое хочет, но высказать его должен, низко поклонившись, извинившись за наглость, хамство и прочие смертные грехи, а требований к объективности его суждений будет на порядок больше, чем к высказываемой большинством точке зрения.
Вот я, давеча, раскритиковал C++. Я его более-менее знаю, но совсем не люблю. Что там началось…
Ничего не поделаешь — традиционализм у отечественной интеллигенции в крови. Может, оно и к лучшему — иногда так проще и тверже стоять на ногах. Меньше риск внезапно оказаться «за бортом истории».
Smashing Magazine
не во что :)
— для меня является очевидным, что чем универсальнее инструмент, тем он более громоздкий и медленный. Почему вы не используете швейцарский нож для повседневного приема пищи?
— есть задачи, с которыми реляционные БД справятся лучше. Автор же предлагает использовать одну БД везде и всюду, судя по комментарию:
Возвращаться на реляционные — боже упаси
— и вот эта цитата:
Нет, я не буду рассказывать вам про MongoDB или ещё какую неполноценную «убийцу SQL».
Я расскажу вам про другого «убийцу SQL».
Я в этой фразе:
Возвращаться на реляционные — боже упаси
увидел следующий смысл: «я ненавижу реляционные базы и мне неприятно ими пользоваться». Не меньше, но и не больше. Просто желание такое. При этом он всю дорогу говорит о том, что реляционные БД используются в случаях, когда они неэффективны. Где он что-то писал типа «не используйте реляционные базы НИКОГДА»? Посыл статьи — не использовать их там, где они неудобны. И много восторга от того, как это хорошо у него самого получилось.
Я расскажу вам про другого «убийцу SQL».
Юмор у всех разный. Один пошутил, другой не понял…
Почему вы не используете швейцарский нож для повседневного приема пищи?Потому же почему вы не пользуетесь всеми этими приборами для повседневного приёма пищи:
есть задачи, с которыми реляционные БД справятся лучше. Автор же предлагает использовать одну БД везде и всюду, судя по комментарию:Озвучьте эти задачи, пожалуйста. Автор утверждает, что графовые СУБД справляются с задачами реляционных лучше, чем реляционные с задачами графовых, так что нет смысла ограничивать себя таблицами, если можно сразу рисовать графы.
Я расскажу вам про другого «убийцу SQL».Про полноценную убийцу SQL.
Они не удовлетворяют требованиям ACID (Атомарность, Согласованность, Изолированность, Надёжность). OrientDB этим требованиям удовлетворяет.
Обоснуйте по каждому пункту, пожалуйста. Желательно с примерами.
Не прочитал и страницы, как наткнулся на раздел:
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.
Ваша цитата, к какой части моего комментария относится?
Некоторые, особо «передовые» программисты, предлагают хранить каждый тип моделей в своей СУБД. «Важные данные» в реляционных, деревья в графовых, а примитивные вообще в словарях. Но подобные подходы вида «всякой задаче свой инструмент» лишь добавляют головной боли (и как следствие багов разной степени тяжести) на тему консистентности данных в разных частях приложения.
Заявление с апломбом, а факты где?
Автор, а вы знаете, что для реляционных СУБД есть стройная реляционная алгебра? То есть корректность построений можно проверить математически.
Можно ли проверить корректность вашей модели?
Или «мамой клянус, правильно работает!»
create property Person.friend linkset PersonЯ где то вычитал, что если переместить документ на который ссылаются через link*, то эта связь ломается. А если в документ добавлять данных и он выйдет за пределы первоначально ему отведенные, то этот документ подлежит перемещению (из mongodb).
Т.е. мы либо не можем расширять документы, либо ломаются связи.
Так ли это, как это «обруливается»?
Или забыть про link* и использовать edge?
The 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) по идентификаторам (массив со смещениями). И нет, это не то же самое, что первичный ключ в РСУБД и той же Монге, где значение этого ключа можно указывать своё, а не строго автоинкремент, из-за чего вместо массива приходится использовать более сложные структуры данных, допускающие пропуски.
Цель — протестировать скорость ссылок «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, но они мне не часто встречаются, те что встречаются обычно решаются «в лоб» (иногда даже без джойнов).
Покажите свой код. Вот мой: https://github.com/nin-jin/dbench
By 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.
Acknowledged 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/
Например, MongoDB по умолчанию не дожидается записи в журнал, чтобы ответить «спокойно, я всё сохранила».Это не влияет на скорость записи в бд, влияет на скрипт, будет он ждать или нет ответа и скорость отправки последовательных операций.
Для проверки OrientDB я запускал 10 потоков, OrientDB кушал ~95% cpu, т.е. выдавал все что мог, поэтому ожидание в скрипте не влияло.
В купе с отсутствием транзакцийДа, транзакции — серьезный фактор, поэтому ArangoDB стоит в списке на рассмотрение.
Вот кусок кода, для OrientDB один запрос без смещения, на поле name сделан индекс SB-Tree, без индекса работает в 400 раз медленнее — т.е. индекс работает.
Тесты запускал в 1 поток, сейчас запустил в 10 потоков (итого 1000 запросов по 100 документов):
OrientDB: ~7.3 сек
MongoDB: ~0.4 сек
будет он ждать или нет ответа и скорость отправки последовательных операций.Запись без ожидания ответа, не считая последнего документа, который ждет ответа записи, что означает что запись завершена.
Это не влияет на скорость записи в бд, влияет на скрипт, будет он ждать или нет ответа и скорость отправки последовательных операций.Ну да, это влияет на бенчмарки :-)
parents = db.user.find({'_id': {'$in': list(parents)}})
Я так понимаю тут возвращается курсор и нужно развернуть его в список:
parents = list(db.user.find({'_id': {'$in': list(parents)}}))
Что показывает explain?
100 запросов вы делаете разные или одинаковые?
Я так понимаю тут возвращается курсор и нужно развернуть его в список:Упс, пропустил, в первой версии был пербор в цикле, поправил (стало медленнее в 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.sh
OrientDB: ~6 сек и ~18 сек
MongoDB: ~1.3 сек и ~3.8 сек
Запустил на 1М документов, если курсоры не отвалятся то выложу результат.
100k
mongodb: 0.6s, 3s
orientdb: 4s, 16s
1M
mongodb: 0.9s, 3.5s
orientdb: 5s, 18s
--journalCommitInterval 2Это видимо что-бы монга медленнее добавляла данные, а для надежности в реальных проектах просто делают реплику. А в orientdb и postgresql какой интервал сброса на диск (не в кеш ОС)?
Ну да ладно, речь про чтение,
а выборка связанных записей в постгресе в 2 раза быстрей, чем в монге и ориенте.Потому что там та же выборка диапазона по индексу (что и в первом тесте). В монге можно сделать так же (doc.parent) и она будет такой же быстрой, т.е. монга дает варианты где у каждого свои плюсы, минусы. То же самое можно сделать и в orientdb, но он медленнее (судя по первому тесту), кстати в postgresql тоже можно запихнуть массив, в json*.
Это видимо что-бы монга медленнее добавляла данные, а для надежности в реальных проектах просто делают реплику.Нет, это чтобы быть уверенным, что данные не потеряются. Реплика тут ничем не поможет (пример — нода отвечает, что сохранила и тут же падает, не успев реплицировать).
А в orientdb и postgresql какой интервал сброса на диск (не в кеш ОС)?Без понятия, но увеличение его для монги погоды не делало.
В монге можно сделать так же (doc.parent) и она будет такой же быстройИ также придётся париться с сохранением порядка комментариев, которое я поленился пока реализовывать для постгреса, а надо прикрутить для чистоты эксперимента.
кстати в postgresql тоже можно запихнуть массив, в jsonЧерез костыль в виде hstore? Ну да, можно. Прелесть ориента в том, что можно иметь приемлемую скорость и хороший потенциал горизонтального масштабирования, не вывихивая себе мозг и не утапливая проект в грудах запутанного кода. Банально, в админке, чтобы перейти к связанной сущности достаточно кликнуть по ссылке, а не писать sql запрос — это значительно упрощает и ускоряет дебаг, так как связи между сущностями явные.
В поле можно хранить json-документ, по нему можно даже некоторые индексы построить. Правда валидация идёт лесом, памяти больше ест и запросы похожи на перловые заклинания.
Реплика тут ничем не поможет (пример — нода отвечает, что сохранила и тут же падает, не успев реплицировать).В монге как раз это продумано, вы при записи указываете сколько нод «запишет» ваш документ прежде чем вы получите ответ, например при w=2 — минимум две ноды получат документ прежде чем вы получите ответ о записи (при этом даже можно журналирование отключить).
А в случае с журналированием (что и в одиночном postgresql/orientdb) вы как раз имеете период когда данные еще не сбросились на диск.
И также придётся париться с сохранением порядка комментариевНе для всех задач нужен порядок, (например комменты можно посортировать уже на клиенте), даже если добавить поле очередности комментов — оно все равно будет быстрее чем doc.child т.к. будет выборка одного диапазона из индекса (как в первом тесте).
В отношении родитель-дети порядок обычно имеет значение. Я уже добавил постгресу отдельное поле для указания порядка — инсерты стали занимть по времени столько же, сколько и в ориенте. На селектах, конечно, почти не отразилось.
Ещё добавил графовое апи для ориента — оно раза в два медленнее при записи и при переходах по ссылкам.
Если не пугает перспектива потерять данные при обесточивании обеих нодШанс потерять данные при любом подходе есть, хоть и мизерный, что-бы снизить риск обесточивания «обеих» нод, их размещают в разных ДЦ.
На селектах, конечно, почти не отразилось.Как я и предположил.
Я уже добавил постгресу отдельное поле для указания порядка — инсерты стали занимть по времени столько же, сколько и в ориентеВместо инкремента, который будет кривой в случае удаления комментов, можно писать timestamp, тогда будет быстро как в изначальном варианте (тем более поле «время» обычно есть у комментариев любого проекта).
Временная метка ничем не лучше айдишника. Проблемы начинаются при переносах веток. Конкретно для комментов это не очень актуально, но обычно порядок элементов в списках всё же не зависит от времени создания этих элементов.
Только вот дожидаться реплики из другого ДЦ придётся дольше, чем от сброса журнала на диск.Сейчас померял пинг из Амстердама (Digital Ocean) до Франкфурта (Leaseweb) = 1 — 1.5ms
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 ms
Даже если реплика для одиночной команды будет 10-20мс — это зачастую норм, зато общая производительность будет выше (для параллельных команд).
Кроме того монга дает возможность задавать «надежность записи» на каждую команду, неважные данные типа логов можно писать с w=0 без ожидания, что дает дополнительную скорость для клиента. Вообщем монга дает ассортимент в этом плане, регулятор между скоростью и надежностью.
Ну да ладно, сильно отклонились от сабжа, получается OrientDB медленнее в 2-5 раз, но ради удобства жертвовать скоростью иногда приемлемо (например использовать python вместо c++ для веба).
Конкретно мне понравились линки, ну и ребра (edge), вторые я не так часто использую, а линки не привносят столько удобств что-бы терять в скорости в 2+ раза. Конечно там ещё есть транзакции, но для веба обычно достаточно атомарных комитов (+ ради транзакций можно ещё пощупать другие решения).
Вообщем, OrientDB интересен, но для моих задач монга пока лучше.
Разные данные имеют разную ценность, что, вроде, очевидно. Вы же не будете для хранения промежуточных данных, которые пересчитываются за час 5 дубликатов в 5 разных az/dc, если у вас допустима такая задержка (на пересчёт)?
Монга просто дает разные варианты (в отличие от других*), вы уже сами определяете что вам нужно.
Я не сторонник половинчатых решений с неопределённым поведением. Если мне не важно записались ли данные, то я продолжу исполнение вообще не дожидаясь ответа от субд. Если же я дожидаюсь ответа, значит мне важно, прошла ли запись успешно, и если нет, то ожидаю получить информацию о произошедшей исключительной ситуации, какой бы она ни была. А не так, что «палка иногда стреляет, но редко и тихо».
Если мне не важно записались ли данные, то я продолжу исполнение вообще не дожидаясь ответа от субд. Если же я дожидаюсь ответа, значит мне важно, прошла ли запись успешно, и если нет, то ожидаю получить информацию о произошедшей исключительной ситуации, какой бы она ни была.Вы как раз и описали работу с монгой, но у вас почему-то какая-то претензия.
Luca Garulli теперь вице-президент SAP. Минусовали, вероятно, завистники, которых SAP не купил :).
"Распределенные" обычно имеет другое значение, чем тот тип хранилищ, что подразумевается в микросервисах по умолчанию. Система распределённой становится, но хранилища у каждого сервиса "локальные". И связи внутри них он контролирует, типа не должно быть "висящих" OrderLine без соответствующего Order в сервисе заказов. А что в сервисе контрагентов для Order.customerId не найдётся записи не его ответственность, а зачастую и ошибкой не считается. Необходимость ссылочной целостности зачастую преувеличена.
Боюсь, я недостаточно игрался с OrientDB, чтобы понимать о чём речь. Но в целом в мире MSA связь сущностей разных сервисов осуществляется по идентификаторам и целостность этих ссылок в произвольный момент времени не подразумевается. Даже стремление к ней не подразумевается, если этого нет в требованиях.
DataBase as MicroService
Что за непонятные числа?select expand( friend ) from #19:0
Не пора ли реляционным базам данных на свалку истории?