Релокейт-опрос 2017 (для тех, кто уже уехал). Собрано более 1500 анкет.
×Закрыть

Not Only SQL: ищем альтернативы реляционным базам

Обсуждение побудило меня написать статью о возможных альтернативах реляционным базам данных и SQL Server.

Так уж случилось, что, когда я учился в университете (как и многие мои коллеги), в то время еще не существовало толком никаких альтернатив реляционным базам. Только-только появился алгоритм Map-Reduce (2004), но в продуктах хранения данных он начал использоваться примерно в 2006 и позже. О самом алгоритме я узнал в году, наверное, 2010 (как минимум не раньше — точно не помню), до этого момента я использовал SQL Server и файлы. Облачные хранилища данных появились еще позже — Amazon AWS появился в 2006 и стал более-менее на слуху в 2008 году. Microsoft Azure появился вообще в 2010 и набрал популярность еще через пару лет.

Раньше все данные было принято хранить либо в файлах, либо в реляционной базе данных. Проект без базы данных был чем-то из области фантастики (я говорю в основном про классические «сайты», «сервисы» и «энтерпрайз» решения). Конечно же, были и другие экзотические альтернативы, но они использовались очень редко.

Но время идет, и технологии стремительно развиваются. За последние 10 лет появилось много хранилищ данных на базе MapReduce, а также на базе других алгоритмов и структур данных. Сейчас никого не удивишь длинным списком из существующих хранилищ. Вот только некоторые из них: Google BigTable, Amazon Dynamo, Azure TableStorage, ElasticSearch, MongoDb, Apache HBase, Neo4j, Amazon S3, Azure DocumentDb, Druid и так далее. Причем некоторые из них можно использовать как сервис PaaS (Platform As A Service). PaaS позволяет сэкономить кучу денег, времени и нервов на хостинге и обслуживании хранилища. Многие из них по-настоящему распределенные и масштабируемые горизонтально, в отличие от SQL.

Как работает реляционная база данных

Image source

В основе реляционных баз данных лежит структура под названием b-tree, что накладывает определенные ограничения. Реляционная база данных реализована по ACID модели (Atomic, Consistent, Isolated, Durable). Другими словами, из стандартных Consistency-Availability-Partition Tolerance (статья на тему CAP) реляционная база поддерживает Consistency и Availability. Каждая таблица — это один или более индексов (clustered and unclustered indexes). Каждый индекс представляет собой отдельное b-tree. Встречаются и другие типы индексов, но они редко используются. Для перестроения индекса базе данных может понадобиться считать или записать некоторые страницы с данными с диска, что невероятно медленно. Если у вас в таблице десять индексов, при каждой записи (удалении, вставке или изменении) в таблицу, база данных будет перестраивать все десять индексов. Так как база поддерживает ACID — все операции с данными синхронные, а значит, придется ждать пока все операции перестроения индексов будут завершены перед «коммитом» транзакции. Между скоростью чтения и записи в SQL базе данных всегда есть компромисс. Невозможно одновременно иметь быстрые запись и чтение в реляционной базе данных. Хотите быструю запись — ваши таблицы должны содержать минимум индексов. Хотите быстрое чтение — наоборот нужно создать много индексов, которые покроют все ваши условия в запросах.

Быстрая реляционная база данных

А что если нельзя иметь одновременно быстрые чтение и запись в реляционной базе? Компромисс между чтением и записью можно обойти при помощи создания второй базы, которую называют Data Warehouse — ее оптимизируют под чтение данных и создание сложных отчетов. Таким образом, Operational (OLTP) база поддерживает быструю запись и изменение данных, а Data Warehouse (OLAP) поддерживает быстрое чтение и сложные многоэтажные запросы. Но тут вступает в дело CAP теорема — вы не можете иметь все три свойства CAP одновременно в такой конфигурации. Другими словами, вы не можете транзакционно писать одновременно в Operational базу и в Data Warehouse — транзакция будет распределенной и очень медленной. Базы получаются разделены физически, и данные в Data Warehouse попадают с некоторой задержкой. Следовательно, мы приходим к Eventual Consistency на реляционной базе данных — то, что мы пишем в Operational базу, невозможно сразу же прочитать из Data Warehouse. Реляционные базы данных не масштабируются горизонтально. И никакие Shards и Partitions все равно не помогут победить CAP теорему.

Альтернатива реляционным базам данных

Альтернативные хранилища в основном используют другие структуры данных для хранения, например, LSM, Distributed Hash Table, Inverted Index, Graph или что-то еще более экзотическое. Подробнее про эти структуры данных можно почитать на википедии. По большому счету большинство альтернатив реляционным базам используют разделение записи и чтения в пределах одной базы. Они часто реализуют BASE модель (Basically Available, Soft-state, Eventually-consistent) и жертвуют Consistency в пользу Availability и Partition Tolerance. Если рассмотреть Eventually-consistent хранилище на примере MongoDb — MongoDb выигрывает в производительности записи у SQL, потому что вторичные индексы обновляются не сразу при записи, а асинхронно — через некоторое время. Если у вас несколько партишенов и есть копии данных (реплики), они также обновляются асинхронно через некоторое время. Другими словами, если вы делаете запись и сразу же пытаетесь найти записанный документ — есть шанс, что он не будет найден. Либо вы найдете предыдущую (устаревшую) версию документа. Это и есть отсутствие строгой целостности (strict Consistency). Объяснить все нюансы с Partition Tolerance и Consistency потянет на отдельную статью — кому интересна тема рекомендую почитать NoSQL Distilled — там очень хорошо раскрыта тема CAP теоремы и ее следствий. Стоит упомянуть, что многие из альтернативных хранилищ поддерживают транзакционность в пределах партишена либо глобально по требованию за счет распределенной транзакции, что позволяет писать, используя привычный подход ACID-транзакций.

Event Sourcing

Image source

Очень мощная альтернатива реляционной модели — Event Sourcing. В привычной нам реляционной модели мы храним объекты и связи между ними. При изменении объекта мы просто перезаписываем старый объект новым. Другими словами, мы всегда храним только одно состояние объекта — последнее сохраненное. В реляционной модели, думаю, всем знакомы проблемы с синхронизацией, производительностью при изменении одних и тех же данных, deadlocks.

Event Sourcing — это когда каждое изменение в доменной модели записывается как событие (event). Все события immutable, таким образом, хранилище представляет собой append-only log, где ничего не удаляется и не меняется. За счет этого сразу решается куча проблем с синхронизацией и масштабированием записи. Также, как побочный эффект, появляется полный лог всех операций в системе и возможность реконструировать любой доменный объект на любой момент времени в системе. Это может очень помочь при отладке и воспроизведении ошибок. Конечно же, есть и минусы Event Sourcing — в первую очередь это бОльший объем данных и невозможность выполнять привычные запросы select ... where ... в таком хранилище. Проблема с запросами легко решается использованием отдельного хранилища для чтения. Проблема с объемом данных надуманная, так как хранение данных сегодня стоит копейки по сравнению со стоимостью трафика или процессорного времени.

Любая операции в модели Event Sourcing выглядит так:
Given начальная последовательность событий;
When выполняем операцию (команду);
Then в лог записывается одно-или-более событий или Exception (ошибка).

Как можно заметить — все вычисления с доменной моделью можно реализовать в функциональном стиле без побочных эффектов (side effects).
Тема очень интересная и очень обширная, поэтому я упомяну, что Event Sourcing часто используется вместе с Domain Driven Design (DDD) и Command Query Responsibility Segregation (CQRS) и перейду к конкретному примеру на Azure Table Storage.

Event Sourcing на Azure Table Storage

Я хочу показать пример, как можно использовать Azure Table Storage для построения высоконагруженной системы с Event Sourcing моделью. Давайте попробуем смоделировать что-то простое — например, счет игрока в онлайн-казино. У нас есть пользователь, который может пополнять свой счет, делать ставки, получать выигрыш и снимать деньги. Когда на счету нет денег — пользователь не может делать ставки. Мы можем смоделировать следующие события для пользователя: MoneyDeposited, BetPlaced, WinReceived, MoneyWithdrawn.

Azure Table Storage — высокопроизводительное облачное хранилище от Microsoft. Оно очень простое — вы можете создавать таблицы, в которых по умолчанию есть столбцы PartitionKey (string), RowKey (string). Также вы еще можете иметь 255 столбцов для хранения произвольных данных. Запросы поддерживаются только для PartitionKey и RowKey, для всех остальных случаев производительность запросов очень низкая, так как никакие поля, кроме PartitionKey и RowKey, не индексируются. Поддерживается транзакционность на уровне Partition в пределах 100 записей. То есть можно атомарно писать до 100 записей с одинаковым PartitionKey. В общем случае в таком хранилище при использовании Event Sourcing нам нужно три поля: PartitionKey — aggregate Id, RowKey — event Id, Data — event body (произвольный JSON).

В случае с казино наш игрок является aggregate (из терминологии DDD) или границей транзакции. Игрок взаимодействует только с казино, и мы его можем полностью изолировать от других игроков. Таким образом, PartitionKey в нашем хранилище будет aggregate Id — уникальное Id игрока. RowKey будет использоваться как последовательный номер события в потоке.

В таком решении у нас будет количество партишенов равно количеству игроков. Если у нас миллион игроков — значит будет миллион партишенов в таблицы. В Azure Table Storage нет ограничений на количество партишенов, и это очень удобно. В пределах одного партишена производительность до 2000 IOPS.

Но все было бы слишком просто, если бы не две проблемы — многопоточное обновление данных и вычисление текущего состояния. Сколько денег на счету у игрока? Как поддерживать транзакционность всех операций и сохранение инвариантов: «Баланс на счету не должен быть отрицательным»?

С многопоточным обновлением данных (точнее, c записью нового события) есть как минимум два решения. Первое и самое очевидное — не используйте многопоточность. Например, можно реализовать actor-based решение и всегда обрабатывать запись в один поток. Второе решение — используйте optimistic concurrency. Можно добавить специальную запись StreamHeader, в которой будет храниться номер последнего записанного события и другие метаданные. StreamHeader мы будем обновлять в момент записи событий. В Table Storage у каждой записи есть ETag, на базе которого реализовано optimistic concurrency. Если кто-то уже перезаписал StreamHeader — мы получим Exception при попытке записи.

Вторая проблема — вычисление текущего состояния (баланса) игрока решается похожим способом. Достаточно просто добавить в запись StreamHeader текущее состояние счета. Как альтернатива — нам нужно перечитывать весь поток событий? чтобы выполнить какое-то действие (команду).

Так как мы можем писать до 100 записей транзакционно, и при записи проверяется был ли изменен перезаписываемый объект — со специальной записью StreamHeader мы можем гарантировать целостность данных в пределах партишена.

Внимательный читатель заметил, что в этом решении нет ни одного вторичного индекса. Например, мы не можем искать по имени игры или по сумме ставки. Для сложных запросов нам нужно другое хранилище — например, DocumentDB, где мы сможем делать сложную аналитику и отвечать на вопросы «сколько игроков поднимают ставку более чем в два раза перед тем, как все проиграть». Я бы назвал Azure TableStorage хранилищем, оптимизированным для записи и хорошим выбором для EventSourcing.

Eventual Consistency решает проблемы с масштабированием

Я понял за годы работы программистом, что многие реальные бизнес-процессы не требуют строгой консистентности и транзакционности всех операций. Как пример — продажа товара в интернет-магазине. Представьте себе у вас есть 10 000 000 покемонов и весь мир потенциальных покупателей. Можно взять sql и реализовать примерно такую логику — при попытке покупки мы делаем запрос в базу, если покемоны еще есть — покупку разрешаем, иначе говорим, что покемоны закончились. Для этого нам понадобится одно физическое место (табличка в базе), где мы будем вести учет проданных покемонов. Либо счетчик проданных покемонов, который транзакционно обновляется при каждой продаже и опрашивается при каждой попытке купить. Это и есть наше узкое место в системе.

Можно сделать все по-другому. Если спросить любого продажника — ему все равно, сколько у вас товара на складе. Он будет рад продать любое количество — чем больше, тем лучше. Так устроена работа продажника, да и многих бизнесов: утром — деньги, вечером — стулья. И даже если стульев нет, все будут рады получить деньги утром. =)

Мы не будем проверять наличие покемонов при каждой покупке. Вместо этого мы будем продавать покемонов до момента, когда уже будет точно понятно, что покемонов больше нет. Мы убираем транзакционность из нашего решения и избавляемся от проблемы Consistency нашего глобального счетчика. Вместо проверки наличия при каждой попытке купить можно раз в минуту (в час или в день) проверять, сколько осталось покемонов, и закрыть продажу, как только мы точно знаем, что покемонов больше нет в наличии. Может получиться так, что мы продадим немного больше товара, чем реально есть на складе. Но это уже будет не наша проблема, а проблема директора (владельца), где достать больше товара. Обычно она решается пополнением склада или возвратом денег клиентам. Я вас уверяю, лучше иметь проблемы со сверхпродажами вместо проблемы с тормозами вашего интернет-магазина или что вы там программируете. =)

Context is a king

В контексте хранилищ данных очень важна модель данных и приложения. Действительно реляционных данных в мире мало. Реляционная модель (как и любая другая модель) — всего лишь наша попытка представления реальности в цифрах. Есть множество других моделей, которые игнорируются в силу доминирования реляционных баз данных. Например, вот этот текст, который вы сейчас читаете, можно рассматривать по-разному. С точки зрения реляционной модели здесь есть слова, предложения и абзацы, которые составляют текст. А можно рассматривать как последовательность изменений, которые я вносил в текст в течение нескольких вечеров, пока я его писал. Также его можно рассматривать как один целостный документ — «blob», который имеет ссылку в интернете и который имеет смысл только как единое целое. Или можно рассматривать текст как вектор слов на русском языке. Или как массив символов кириллицы. Ну и так далее — текст один, а моделей множество. Все зависит от поставленной задачи. Все задачи решать при помощи реляционной модели данных и SQL — плохая идея.

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

P.S. На моей последней работе вообще нет SQL, и я считаю это приятным бонусом ко всему остальному.

Лучшие комментарии пропустить

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

Я понял за годы работы программистом, что многие реальные бизнес-процессы не требуют строгой консистентности и транзакционности всех операций. Как пример — продажа товара в интернет-магазине
Это если магазин не заботится о своей репутации. Я один-два раза не смогу купить в интернет-магазине товар и поставлю его в черный список и другим рекомендовать не буду. И мне все равно, что они пожертвовали консистентностью в угоду скорости работы.

прочитав этот перл «Многие из них по-настоящему распределенные и масштабируемые горизонтально, в отличие от SQL.» задумался — то ли автор неграмотен в теме СУБД, то ли применяет прием маркетологов , подменяя понятия чтобы продать что-то

SQL — это язык запросов. он не может быть распределенным и масштабируемым.

и наличие PaaS и облачных хостингов никак не кореллирует ни с используемым языком запросов ни с типом СУБД
например тот же Azure использует диалект MS SQL

Но это уже будет не наша проблема, а проблема директора (владельца), где достать больше товара. Обычно она решается пополнением склада или возвратом денег клиентам. Я вас уверяю, лучше иметь проблемы со сверхпродажами вместо проблемы с тормозами вашего интернет-магазина
Как покупатель негодую с такого подхода.

148 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

Интересно, google spanner — sql или nosql решение? )

В Facebook подсказали хорошую статью по теме

PACELC. The lack of the CAP Theorem is addressed in an article by Daniel Abadi in which he points out that the CAP Theorem fails to capture the trade-off between latency and consistency during normal operation, even though it has proven to be much more influential on the design of distributed systems than the availability-consistency trade-off in failure scenarios. He formulates PACELC which unifies both trade-offs and thus portrays the design space of distributed systems more accurately. From PACELC, we learn that in case of a Partition, there is an Availability-Consistency trade-off; Else, i.e. in normal operation, there is a Latency-Consistency trade-off.

Какое хранилище выбрать? — Диаграма

соглашусь, что я перебрал в разделе с базами так как я не знаю все нюансы реализации конректного движка.
Sql баз много разных и много версий существует. В разных версиях реализация базы отличается. Я рад что сейчас есть куча оптимизаций в виде write ahead и так далее.
Но у всех баз как раз общее — это b-tree и реляционная алгебра. Насколько я знаю все sql базы начинались с 1-3NF и b-tree. R-tree, hash, heap — все это не относится к реляционной теории.

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

Я думаю поправить абзац про sql. Будет супер если вы посоветуете что конкретно туда написать.

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

Дело никак не в конкретном движке.

Но у всех баз как раз общее — это b-tree
R-tree, hash, heap — все это не относится к реляционной теории.

B-дерево никак не относится к реляционной теории, оно ей просто ортогонально. Реляционная теория (будем пользоваться этим выражением) требует только одного: чтобы кортежи были уникальны — потому что она работает в понятиях математического множества, в котором совпадающих элементов не может быть. И то — в реальных SQL средствах это не обязательно — поэтому, например, SELECT DISTINCT это другой запрос, чем просто SELECT, и последний может возвращать идентичные строки.

В-дерево же является средством обеспечить доступ по упорядочению ключа, причём с произвольной точки, за теоретически разумное время — O(N*log(N)). То есть это помощь в реализации запросов по возрастанию или убыванию некоторого индекса. Оно было раньше практически единственным средством потому, что
1) не было нормальной теории, например, построения хэшей на диске (где-то сразу, как её проработали, появились средства вроде Cassandra);
2) в условиях тогдашних мощностей железа было проще организовать 1 движок на все случаи, чем держать несколько движков на разные форматы индексов (вспомним, что ещё в конце 90-х было более чем дофига систем под DOS, страдавших от 640KB ограничения на всё, включая код, данные и ОС).

B-дерево обеспечивает и упорядочённый доступ, и уникальность. Поэтому и стало временной базой, несмотря на чрезмерную универсальность и соответственно торможение или затраты места для конкретных случаев.

Но даже для этих же целей сейчас есть log-structured merge, которое можно и нужно использовать вместо B-tree во многих случаях (если не в большинстве — на SSD для эффективности и скорости, на HDD для скорости, и даже в RAM). Оно по скорости практически совпадает с «чистым» event sourcing, но, в отличие от последнего, штатно предполагает средства сжатия в хранилище.

Понимание этой области у Вас застряло на уровне примерно 2000-го года, если не раньше. Именно около 2000-го появилось уже упомянутое log-structured merge, немного позже — качественные хэши на дисках. Примерно тогда же начали массово использовать встроенные (они же кластерные) индексы. Реляционные СУБД сегодняшнего образца очень резко отличаются от таковых 15 лет назад. Так что рекомендую обновить свои представления.

Если что-то не помещается в памяти, IO начинает играть важную роль в любом случае — кэп
Чтобы что-то написать про SQL, может лучше все-таки для начала что-то почитать?

Но у всех баз как раз общее — это b-tree и реляционная алгебра. Насколько я знаю все sql базы начинались с 1-3NF и b-tree. R-tree, hash, heap — все это не относится к реляционной теории.
Эквивалентное высказывание: у всех машин общее — колеса и руль. И не поспоришь ведь.
SQL является комбинацией РА и РИ, и больше основан на РИ чем на РА. Нормальные формы больше относятся к академическому представлению реляционной модели, чем к реальности в современных СУБД. B-Tree относится к структуре хранения одного типа индексов (из множества других) и тоже не относится к реляционной теории.

Not only SQL ≠ No SQL

SQL це мова запитів і відповідно можливість її використання в СУБД.

Не реляційні БД називаються документарні чи об’єктно-орієнтовані. Другий термін мені менше подобається, але бінарне зберігання документів у полях BSON та побудова звернення в запиті як до об’єкту надає певну леґітимність і такій назві.

Поява ж у переважної кількості найбільш поширених БД (Oracle, PostrgeSQL, MySQL і т.і.) полів для збереження та механізмів обробки та індексації документарних полів взагалі стає ознакою включення об’єктної складової в стандартні інструкції SQL.

Для початку пропоную ознайомитись з Oracle, PostrgeSQL, MySQL, MariaDB і т.і. та можливостями полів для збереження та пошуку документів/об’єктів/JSON данних.

Ієрархії, свого часу були Охілесовою п’ятою реляційних БД, і їх реалізацію вирішували багатьма алгоритмами, від Parent-Child до Nested Set. Ще більшою була проблема невизначеності можливої кількості та складу полів. З появою JSON / BSON полів ці проблеми стали перевагами, як і імплементація шардінґу.

Меморіальний ордер — це єдиний транзакційний документ в банку. Він містить свідчення обмеженого та суто визначеного характеру, сума, валюта, реквізити двох рахунків, призначення, номер документу та часовий штамп. Його виконання призводить до зміни залишків на рахунках, і в переважній кількості випадків, відразу на значно більшій кількості аніж зазначено в самому документі. Зазвичай немає сенсу реалізовувати його документарно, оскільки зв’язки дуже добре описані та повинні зберігати цілісність всієї транзакції. Я пишу зазвичай, тому, що є випадки і протилежні, приклад коли такий документ приходить з ЕЦП через систему Інтернет-банкінгу, або навіть електронною поштою. Але виконання такого документу всеодно відбувається в реляційній БД з суворим контролем цілісності транзакції.

Повідомлення системи S.W.I.F.T. — також є транзакційним документом в банку, але окрім того є також і інформаційним документом (наприклад інформаційним листом або повідомленням про фактичний залишок на рахунку). S.W.I.F.T. документ може містити довільну кількість полів загалом, але в межах відповідного типу документу їх склад регулюється. Так транзакційний документ може містити невизначену кількість полів, що містять перелік кореспондентських рахунків (траса платежу), або інформаційний документ може містити невизначену кількість полів з історією зарахувань/відрахувань з рахунку. Зберігати такий документ в реляційних БД у вигляді полів таблиці безглуздо.

Але і тримати окрему документарну БД як сховище для S.W.I.F.T. документів сьогодні теж виглядає дещо сумнівним рішенням. Навіщо плодити зоопарк, коли можна користуватись однією СУБД що вміє і вдало працює як реляційно так і документарно?

Ще одним важливим прикладом можна назвати варіант, що використовується провідними гравцями ринку, коли товари в магазині зберігаються в реляційній системі, але з кожного варіанту товару (колір, розмір, комплектація, бонусна програма і т.і.) утворюється його документарне представлення. Такий собі кеш, до якого і звертаються всі скрипти (наприклад каталогу товарів, пошукові індекси). Всі зміни властивостей товару в реляційному сховищі супроводжуються оновленням відповідних документарних представлень товару. Якщо є бажання зберігати історію змін товару — будь ласка, хочете зберігайте стани, хочете інкрементально.

Що стосується продажу товару, якого немає на складі, запропонованого автором вказаної вище статті, можу лише розвести руками, якщо бізнес дозволяє, будь ласка, робіть такий алгоритм, але майте на увазі, що наслідки можуть вийти за рамки програмної реалізації.

Зберігати чат записи в реляції також безглуздо як і проводити транзакції в документарці. Це не спір між моделями, це розуміння інструментів та їх застосування.

Отже перестаньте дивитись на данні виключно як на одну модель, реляційну чи документарну, байдуже.

Використовуйте інструменти за призначенням!

Ієрархії, свого часу були Охілесовою п’ятою реляційних БД, і їх реалізацію вирішували багатьма алгоритмами, від Parent-Child до Nested Set. Ще більшою була проблема невизначеності можливої кількості та складу полів. З появою JSON / BSON полів ці проблеми стали перевагами, як і імплементація шардінґу.

Перевагами? Вы тоже самое могли сделать 10 лет назад используя xml и xpath. Что глобально поменялось с появлением json полей? это просто фича поддержки формата. никакого усовершенствования реляционой модели обработки данных здесь тоже нет. Возможности документных баз шире чем возможность писать sql для json поля — про скорость таких решений я вообще молчу. Для анализа иерархий документые и реляционные базы все так же крайне неудачные инструменты. Хранение и процессинг иерархий профиль графовых баз. Они и места на диске буду в разы меньше для представления таких данных, на запросах будут требовать в разы меньше усилий и скорость обработки в десятки, а иногда и сотни раз будут давать быстрее . В чем примущества РСУБД попрежнему непонятно.

Что глобально поменялось с появлением json полей?
По-перше імплементація безпосередньо в SQL запиті, по-друге їх індексація, по-третє метод збереження в BSON полях безпосереньо бінарного представлення об’єкта.
никакого усовершенствования реляционой модели обработки данных здесь тоже нет.
Я жодним чином не писав про удосконалення реляційної моделі, звідки Ви то взяли? Мова запитів збагатилась? — так. Реляційні СУБД отримали додаткові переваги, поглинувши переважну більшість фіч документарних СУБД? — так. Але реляційна модель залишилась незмінною. Не наділяйте мій текст власними домислами.
Возможности документных баз шире чем возможность писать sql для json поля
Безперечно, я і не наполягав на зворотньому.
про скорость таких решений я вообще молчу.
Ну то не мовчіть, якщо Вам є що сказати, буду радий побачити порівняльні тести. Це не стьоб, давно хотів зрозуміти що до чого в швидкостях, просто досліджувати самому часу не було. Якщо є що показати буду вдячний.
Хранение и процессинг иерархий профиль графовых баз.

В чем примущества РСУБД попрежнему непонятно.

Вище ТС вже навів класну діаграмку, я її повторю cdn-images-1.medium.com/…​P4HSIx95ZBVla7tjluhLg.png

Використовуйте інструменти за призначенням!

Ну то не мовчіть, якщо Вам є що сказати, буду радий побачити порівняльні тести. Це не стьоб, давно хотів зрозуміти що до чого в швидкостях, просто досліджувати самому часу не було. Якщо є що показати буду вдячний.
Тут интересный момент выходит — вы говорите о преимуществах работы с иерархиями в json движком РСУБД на основании чего? Догадок, прес релиза вендора движка СУБД, к чему ваш пост выше вообще не понятно в таком случае.
Використовуйте інструменти за призначенням!
Хранение и чтение данных из индексированного json поля это предназначение РСУБД?
Вы пишите много нелогичных вещей, я мог бы привести в сравнение по вашей просьбе элементарную скорость поиска в иерархии вложенностей просто графовой базы с реляционной, но почему-то не вижу в этом никакого смысла пока.
Догадок, прес релиза вендора движка СУБД
Ви вже не вперше згадуєте прес релізи вендора як фундамент моїх стверджень. Це такий натяк на сумніви в моєму досвіді? Ну то не майте сумніву це з досвіду практичного застосування.
вы говорите о преимуществах работы с иерархиями в json движком РСУБД
Перечитайте уважно текст ще раз. Я стверджую, що реалізація JSON полів в РСУБД створює можливості простого та достатньо гнучкого механізму роботи з ієрархіями якого раніше в СУБД не було, і доводилось користуватись обхідними механізмами, коен з яких у порівнянні з JSON реалізацією мав недоліки (або довго обходити, або перезаписувати у разі зміни і т.і.) і був значно коштовніший за використання зовнішньої документарної СУБД. А тепер ці недоліки нівельовано і використовувати ієрархії в РСУБД стало значно зручніше, а отже це треба враховувати у той момент часу, коли раптово засвербить поставити документарну СУБД для обслуговування РСУБД в частині ієрархій.
Вы пишите много нелогичных вещей
З ким не буває, буду вдячний за виправлення :)
я мог бы привести в сравнение по вашей просьбе
Якщо у Вас є натхнення та час, буду вдячний, але жодним чином не мав це на увазі. Ще раз повторюю, якщо у Вас вже є результати тестів, я буду вдячний якщо Ви ними поділетесь. Це не змушення Вас зробити щось за мене, я просто запитав інформацію, базуючись на якій Ви стверджували про значні переваги у швидостях, бо мені ця тема цікава, але часу досліджувати не мав.
З ким не буває, буду вдячний за виправлення :)
Вот нелогичный момент.
А тепер ці недоліки нівельовано і використовувати ієрархії в РСУБД стало значно зручніше, а отже це треба враховувати у той момент часу, коли раптово засвербить поставити документарну СУБД для обслуговування РСУБД в частині ієрархій.

Документные базы не ставят для «обсуживание иерархий», как вы выразились. Так как это накладно делать в самих документных базах. Иерархия это отношения — документные базы работают крайне плохо с отношениями, еще хуже чем реляционные. Нелогично, что когда некоторые вендоры добавили в свои движки поддержку json полей, у людей появилась иллюзия, что это отличные инструмент решения работы со сложными иерархиями в РСУБД — это вообще больше пользы чем вреда несет. Но для вендоров РСУБД это еще одна фича, которая так же неудобна как Xml + XPath в движке РСУБД при обработке данных — просто благодаря более широкому распространению JSON сейчас нежели XML 10 лет назад, это будут использовать, что бы продавать, а любители дорогих космодров и универсальных решений будут везде это тулить и еще больше взрывать мозг перенося как можно больше логики в SQL, только теперь там кроме колонок и строк еще будут обрабатываться максимально денормализированные структуры данных.

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

Так, здається я розумію в чому проблема з вендорами. Ви певно вирішили, що мені подобається якась конкретна СУБД або вендор і я жадаю щось продати. Якщо я не помиляюсь. Тож коли так, то буду змушений розчарувати Вас та запевнити, що я є прихильником відкритого коду та піблічних ліцензій. Тому при всій повазі до Oracle я буду радше орієнтуватись та намагатись вирішити задачу на PostrgeSQL, при тому що MySQL пішов далі і розвиває документрану частину краще, я все ж намагатимусь скористуватись MariaDB і т.і.

З приводу універсальності рішень та перенесення логіки в SQL — це два дуже великих питання, кожне з яких базується на доцільності. Не думаю що в рамках коментарів я готовий їх обговорювати. Скажімо так, використовуйте інструменти за призначенням. Є рішення в яких плодити зоопарк СУБД просто марна трата часу та ресурсів, або взагалі просто не вірна реалізація потрібної логіки. Натомість є задачі в яких виключно поділ на різні СУБД є єдиним вірним рішенням. Сферичного коня в вакуумі обговорювати це просто марнування часу.
Теж саме стосується бізнес логіки в межах та за межами СУБД. Величезне питання до якого загалом ставлять як до однозначного не є таким однозначним. Є випадки, коли безперечною є винесення БЛ з БД та 100% впровадження її на рівні серверу додатків. Також є рішення, де взагалі не треба питати як реалізована система зберігання данних в БД, та можна повністю покластись в цьому питанні на ORM рішення. Але це взагалі не виключає ситуацій, коли БЛ може бути реалізована скриптами рутин БД! Полемізувати де повинна бути реалізована БЛ відносно до згаданого коня — марно гаяти час.

Я також не хочу вступати в полеміку стосовно того що було б краще в реалізації Xml + XPath, JSON чи YAML. І не тому що не хочу, а тому, що реалізовано саме JSON. Це факт що стався, прийміть його як є.

и еще больше взрывать мозг
 — жах якийсь!!
я мог бы привести в сравнение по вашей просьбе элементарную скорость поиска в иерархии вложенностей просто графовой базы с реляционной
Так приведите, почему нет?
SQL> select count(*) from t_user;

  COUNT(*)
----------
    100000

Elapsed: 00:00:00.53
SQL> select count(*) from t_user_friend;

  COUNT(*)
----------
     68579

Elapsed: 00:00:00.00
SQL> with fr (user_1, user_2, hlevel) as (
  2  select user_1, user_2, 1 from t_user_friend
  3    where  user_1>1
  4    union all
  5    select e.user_1, e.user_2, m.hlevel + 1 from  t_user_friend e
  6    join  fr m  on (m.user_2 = e.user_1)
  7  ) select count(distinct user_2), max(hlevel) from fr where hlevel <20;

COUNT(DISTINCTUSER_2) MAX(HLEVEL)
--------------------- -----------
                49572          17

Elapsed: 00:00:05.55
SQL> with fr (user_1, user_2, hlevel) as (
  2  select user_1, user_2, 1 from t_user_friend
  3    where  user_1=2
  4    union all
  5    select e.user_1, e.user_2, m.hlevel + 1 from  t_user_friend e
  6    join  fr m  on (m.user_2 = e.user_1)
  7  ) select count(distinct user_2), max(hlevel) from fr where hlevel <20;

COUNT(DISTINCTUSER_2) MAX(HLEVEL)
--------------------- -----------
                 1294          13

Elapsed: 00:00:00.01
SQL>
Поясню. Первый запрос из дерева друзей выбирает уникальных чуваков и максимальный уровень дерева, второй запрос показывает уникальных друзей чувака с номером 2 и уровень дерева для друзей чувака 2.
Ясно что потом нужно еще подсоединить таблицу t_user, если нужны имена, но я надеюсь понятно, что это дешевая операция?
Данные я хотел сгенерировать, но чтобы максимально приблизить, так сказать, взял отсюда:
github.com/jhb/neo4j-testdata
но я надеюсь понятно, что это дешевая операция?
Она быстрая в контексте размеры бд, количества обьединений и мощности рабочей станции — но это говорит мало о чем в контексте подхода. Я вижу ничего более чем то, что ваш пк может быстро 17 раз найти по индексу(или сделать table scan) данные в целочисленном поле и небольшой таблице — ок.
Суть глобально же это не меняет поиск в реляционной подход будет прямопропорционально медленней работать размеру базы, в отличии от графовой базы.
pdfs.semanticscholar.org/…​d6f79547fef9407262dbf.pdf
Тут было бы конечно интересно поднять действительно большую базу и сравнить с поиском в глубоком графе. Про читабельность запроса, когда надо в реляционном представлении обойти граф так же говорить не приходиться.
Я вижу ничего более чем то, что ваш пк может быстро 17 раз найти по индексу данные в целочисленном поле и небольшой таблиц

Вообще-то оба запроса — это обход дерева. Первый запрос — полный обход дерева, второй — от конкретного узла, проход поддерева. Это аж никак не «17 раз найти по индексу данные». Да, это просто дерево без реального наполнения. Добавление «полезной нагрузки» в дерево не увеличит существенно время выполнения этих запросов, присоединение таблиц с «реальными данными» в контексте таких запросов вообще не влияет.
Например, с соединением к таблице пользователей:

SQL> ed
Wrote file afiedt.buf

  1  with fr (user_1, user_2, hlevel) as (
  2  select user_1, user_2, 1 from t_user_friend
  3    where  user_1=2
  4    union all
  5    select e.user_1, e.user_2, m.hlevel + 1 from  t_user_friend e
  6    join  fr m  on (m.user_2 = e.user_1)
  7  ) select count(distinct t.name) from fr
  8* join t_user t on t.id=fr.user_2
SQL> /

COUNT(DISTINCTT.NAME)
---------------------
                 1294

Elapsed: 00:00:00.72
SQL> ed
Wrote file afiedt.buf

  1  with fr (user_1, user_2, hlevel) as (
  2  select user_1, user_2, 1 from t_user_friend
  3    where  user_1=2
  4    union all
  5    select e.user_1, e.user_2, m.hlevel + 1 from  t_user_friend e
  6    join  fr m  on (m.user_2 = e.user_1)
  7  ) select count(t.name) from fr
  8* join t_user t on t.id=fr.user_2
SQL> /

COUNT(T.NAME)
-------------
         1300

Elapsed: 00:00:00.02
При желании я могу нагенерировать записей в таблицу «друзей» до глубины 128, к примеру, или сколько нужно? Графовый подход может быть более эффективным в случае, если есть несколько взаимосвязанных иерархий. К примеру, если есть дерево объектов, и атрибуты объектов связаны между собой, в этом случае эффективность выборки данных будет очень сильно зависеть от пути доступа к данным, или от плана выполнения. Это решается правильным выбором структуры хранения данных, возможно, частичной денормализацией. Что же касается действительно реальных запросов, то как только мы добавим в картину необходимость сортировать данные (внутри запроса или в процессе выдачи пользователю), возможность многопользовательской работы, согласованность данных, то какое решение будет лучше?
Опять же — развитие схемы данных, изменение требований к выдаче данных, развитие проекта. Иерархический запрос можно написать (и изменить) за считанные минуты.
При желании я могу нагенерировать записей в таблицу «друзей» до глубины 128, к примеру, или сколько нужно? Графовый подход может быть более эффективным в случае, если есть несколько взаимосвязанных иерархий.

Я сбросил выше статистику, которая показывает что не только, формально там рассмотрен наш пример с обходом просто графа без каких либо вычислений связанных с атрибутами узлов или отношений. Чем глубже граф и чем больше в нем узлов тем более ваш рекурсивный CTE выполнит обращений к общему индексу/таблице по всем отношениям и тем медленее будет время запроса — что впринципе логично.

Это решается правильным выбором структуры хранения данных, возможно, частичной денормализацией. Что же касается действительно реальных запросов, то как только мы добавим в картину необходимость сортировать данные (внутри запроса или в процессе выдачи пользователю), возможность многопользовательской работы, согласованность данных, то какое решение будет лучше?
Графовые базы так же декларируют ACID и даже поддерживают сортировку результирующего набора. Что же касаеться транзакций, неуверен насколько они с этим эффективно справляються, но для меня выбор неочевиден, хотя РСУБД в этом однозначно должны по идее преуспевать. Я с трудом представляю задачи где может потребоваться, что называеться consistency без малейшего посыла к soft state и одновременно использование графовой базы для анализа — сомнительное преимущество. Я больше бы опасался проблем, которые у вас возникнут при обновлении графа, который храниться в денормализированном представлении в реляционной СУБД, особенно если у вас появиться необходимость работать с нескалярными атрибутами при анализе графа и как это будет влиять на эффективность чтения.
Опять же — развитие схемы данных, изменение требований к выдаче данных, развитие проекта. Иерархический запрос можно написать (и изменить) за считанные минуты.
Рекурсивный CTE и SQL занял значительно больше кода нежели тоже самое на cypher для поиска друзей из примера выше. У некоторых вендоров вообще нет инструментария для работы с рекурсивными запросами в SQL, и требует значительных усилий\написания процедурного кода.

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

Еще раз сначала.

я мог бы привести в сравнение по вашей просьбе элементарную скорость поиска в иерархии вложенностей просто графовой базы с реляционной
Дальше Вы приводите блог какого-то чувака, который уверяет что графовая база рвет реляционные в клочья по скорости. Он не приводит каких-то тестовых данных, так что тестовые данные я добыл сам. Не такие как у него, конечно, но достаточные для иллюстрации (как я думал). В том же его блоге есть ссылка на ютуб, где он рассказывает, как их база бороздит их иерархии видов. Там он показывает слайд, в частности, где говорит что время отклика на Оракле растет экспоненциально начиная с глубины дерева 17.
Окей, я показываю что проход по поддереву для глубины 13 занимает пренебрежимо малое время, дальше начинаются какие-то загадочные съезды в стиле
Она быстрая в контексте размеры бд, количества обьединений и мощности рабочей станции — но это говорит мало о чем в контексте подхода.
или
Суть глобально же это не меняет поиск в реляционной подход будет прямопропорционально медленней работать размеру базы, в отличии от графовой базы.
Дальше идет какая-то пдф-ка, где люди сравнивали непонятно что с чем и вывод такой, что с ростом глубины дерева СУБД перестает справляться.
Ну вот допустим проход по поддереву на глубине 128.
SQL> set timing on
SQL> with fr (user_1, user_2, hlevel) as (
  2  select user_1, user_2, 1 from t_user_friend
  3    where  user_1=2
  4    union all
  5    select e.user_1, e.user_2, m.hlevel + 1 from  t_user_friend e
  6    join  fr m  on (m.user_2 = e.user_1)
  7  ) select count(user_2), max(hlevel) from fr  ;

COUNT(USER_2) MAX(HLEVEL)
------------- -----------
        17208         128

Elapsed: 00:00:01.10
SQL> ed
Wrote file afiedt.buf

  1  with fr (user_1, user_2, hlevel) as (
  2  select user_1, user_2, 1 from t_user_friend
  3    where  user_1=2
  4    union all
  5    select e.user_1, e.user_2, m.hlevel + 1 from  t_user_friend e
  6    join  fr m  on (m.user_2 = e.user_1)
  7* ) select count(distinct t.name), max(hlevel) from fr join t_user t on t.id=user_2
SQL> /

COUNT(DISTINCTT.NAME) MAX(HLEVEL)
--------------------- -----------
                10071         128

Elapsed: 00:00:01.24
Второй запрос — это соединение с таблицой t_user чтобы получить имена.
О чем это говорит и о чем говорит тот пример у чувака, где время отклика увеличивалось экспоненциально? Это говорит о том, что запрос был неправильно построен. До какого-то момента промежуточные результаты могли разместиться целиком в памяти, а после какого-то момента начали использоваться временные сегменты на диске.
Делать полный обход дерева и сортировать результаты после соединения со всеми другими таблицами — так же тупо как и, например, запустить декартово произведение двух больших таблиц и потом фильтровать результат.
Я с трудом представляю задачи где может потребоваться, что называеться consistency без малейшего посыла к soft state и одновременно использование графовой базы для анализа — сомнительное преимущество. Я больше бы опасался проблем, которые у вас возникнут при обновлении графа, который храниться в денормализированном представлении в реляционной СУБД, особенно если у вас появиться необходимость работать с нескалярными атрибутами при анализе графа и как это будет влиять на эффективность чтения.
Этот пассаж я вообще не понял.
Возможности документных баз шире чем возможность писать sql для json поля — про скорость таких решений я вообще молчу.
Какие возможности имеются в виду и можно какую-то поддержку слов про «скорость таких решений»?
Для анализа иерархий документые и реляционные базы все так же крайне неудачные инструменты. Хранение и процессинг иерархий профиль графовых баз.
Почему? Я ниже привел пример с «друзьями». Если все данные уже в базе и если эти данные используются другими приложениями, то нет никакого смысла городить еще что-то. Если есть ограничения в бюджете или задача слишком специфична чтобы добавлять базу данных, то возможно, это имеет смысл. Производительность каждого решения — это вопрос правильного моделирования структур данных и запросов (или путей доступа доступа к данным).
Все остальное — это результат кривизны рук.
Какие возможности имеются в виду и можно какую-то поддержку слов про «скорость таких решений»?
Под рукой ничего нету для сравнения скорости, но я априори не ожидаю, что если есть сериализированный документ в поле и таблица вы сможете эффективно применять к этому SQL для типичных задач реляционных баз — эффективно обновить данные в рамках транзакции, сделать группировку, фильтрацию по группе критериев и т.д. предварительно не добавив индекс под каждую отдельную задачу(что наверняка повлечет либо дубликацию данных либо вынесение указателей в ндекс из сериализированного json). А как у нас обстоят дела с индексами кстати? они уже имеют делать групповые и сложные индексы, гео-индексы по атрибутам и т.д. — вообщем типичные вещи для документных баз(как раз таки те самые широкие возможности документных баз).

Я бы Sql + json документ формулу использовал как можно реже впринципе, и без крайней надобности старался не применять. Я с трудом представляю, что может быть хорошей идей взять таблицу и какой-то сериализированный Json обьект и начать искать в нем что-то или joinнить с чем-то в других таблицах, фильтровать, групировать и вообще делать любые операции с данными привязываясь к структуре таблиц и неструктурированного Json поля и все это обрабатывать в sql.
Для меня это звучит во многом бессмысленно — возможно у вас есть хорошие use кейсы, что оправдали себя на практике, охотно ознакомлюсь.

Окей, то есть, сначала:

Возможности документных баз шире чем возможность писать sql для json поля — про скорость таких решений я вообще молчу.
А сейчас:
Под рукой ничего нету для сравнения скорости
Это немного странно, заявлять о чем-то, но не иметь возможности подкрепить какими-то своими результатами или подтвержденными результатами других людей, не?
о я априори не ожидаю, что если есть сериализированный документ в поле и таблица вы сможете эффективно применять к этому SQL для типичных задач реляционных баз

JSON in MSSQL: msdn.microsoft.com/…​-us/library/dn921897.aspx
JSON in Oracle: blogs.oracle.com/…​es_json_within_the_oracle

Я лично с JSON в базе не сталкивался, но с сериализованными данными работал и работаю.
Например, одна из задач была — хранение и подготовка отчетов по данным аудита из разных приложений. Данные хранились в сериализованном виде в CLOB-полях, которые затем трансформировались в стандартные VARCHAR-ы, и затем часть данных извлекалась оттуда и хранилась в виде коллекций, или CSV. Часть данных трансформировалась в реляционную форму, часть оставалась в таком полусериализованном виде. Для преобразований существовали стандартные и собственные типы. Все это можно реализовать в SQL. Естественно, чем «чище» SQL, тем лучше производительность, поэтому встроенная поддержка подобных вещей существенно облегчает и решение задачи, и дальнейшее сопровождение.

Это немного странно, заявлять о чем-то, но не иметь возможности подкрепить какими-то своими результатами или подтвержденными результатами других людей, не?
Вам сбросить сравнение фич вендора документной баз с ссылкой на msdn? Или университетский учебник по алгоритмам и структурам данных? Такой вариант может лучше подойдет?

Более того у нас есть утверждение с которого все и началось —

Ієрархії, свого часу були Охілесовою п’ятою реляційних БД, і їх реалізацію вирішували багатьма алгоритмами, від Parent-Child до Nested Set. Ще більшою була проблема невизначеності можливої кількості та складу полів. З появою JSON / BSON полів ці проблеми стали перевагами, як і імплементація шардінґу.
Мы пока не имеем никакого подтверждения этому.
Данные хранились в сериализованном виде в CLOB-полях, которые затем трансформировались в стандартные VARCHAR-ы, и затем часть данных извлекалась оттуда и хранилась в виде коллекций, или CSV. Часть данных трансформировалась в реляционную форму, часть оставалась в таком полусериализованном виде. Для преобразований существовали стандартные и собственные типы. Все это можно реализовать в SQL. Естественно, чем «чище» SQL, тем лучше производительность, поэтому встроенная поддержка подобных вещей существенно облегчает и решение задачи, и дальнейшее сопровождение.

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

Вам сбросить сравнение фич вендора документной баз с ссылкой на msdn? Или университетский учебник по алгоритмам и структурам данных? Такой вариант может лучше подойдет?
Окей, т.е.
Возможности документных баз шире чем возможность писать sql для json поля — про скорость таких решений я вообще молчу.
это надо понимать как художественный вымысел, опыта работы с такими решениями в SQL нет, а «возможности документных баз шире» — это просто для красного словца?
Ієрархії, свого часу були Охілесовою п’ятою реляційних БД, і їх реалізацію вирішували багатьма алгоритмами, від Parent-Child до Nested Set. Ще більшою була проблема невизначеності можливої кількості та складу полів. З появою JSON / BSON полів ці проблеми стали перевагами, як і імплементація шардінґу.
Мы пока не имеем никакого подтверждения этому.
Это вообще отлично, цитировать фразу другого человека, вырваную из контекста и говорить, что «мы пока не имеем никакого подтверждения этому». Я больше скажу, подобные проблемы если и были, то лет 15 назад в MySQL, PostgreSQL.
Я сталкивался с таким — обычно это переписываеться все с использование серверных языков со статической типизацией, с нормальной поддержкой локалей, типов данных и удобной настройкой сериализиторов, а не ждут расширения SQL API. Вы пытаетесь применить декларативный язык для работы с реляционными структурами данных для того что бы парсить и десериализировать, а потом сереализировать — совсем не по назначению.
Ясно. Ну я тогда отвечу Вашими же словами:
про скорость таких решений для хранилищ данных я вообще молчу.
))
Так транзакційний документ може містити невизначену кількість полів, що містять перелік кореспондентських рахунків (траса платежу), або інформаційний документ може містити невизначену кількість полів з історією зарахувань/відрахувань з рахунку. Зберігати такий документ в реляційних БД у вигляді полів таблиці безглуздо.

Так і не зберігають «у вигляді полів», зберігають за допомогою рядків окремих таблиць і відношення один-до-багатьох. І це ніяк не протирічить звичайним уявам про реляційні DBMS — навпаки, канонічна нормалізація одразу призводить до такого.

«Документарні» БД без прокрустова ложа схеми — корисні у випадках, коли
1) потрібно зберігати довільні набори даних невідомого типу (прийти може що завгодно);
2) реальна схема занадто часто змінюється (фактично це підвипадок випадка 1 з точки зору самої БД);
3) типовим випадком є вибірка і зберігання повного документу, а не окремих полей чи зрізів по полям багатьох документів.

У фінансах це дуже нетипові випадки. А от показ детальних даних товарів (не їх кількості на складі! або групування) — дуже чітко лягає сюди.

Так і не зберігають «у вигляді полів», зберігають за допомогою рядків окремих таблиць і відношення один-до-багатьох. І це ніяк не протирічить звичайним уявам про реляційні DBMS — навпаки, канонічна нормалізація одразу призводить до такого.
Дякую за виправлення.
«Документарні» БД без прокрустова ложа схеми — корисні у випадках, коли
доповню корисності: 4) повновтекстовим та неточним пошуком.
У фінансах це дуже нетипові випадки.

Насправді не такі вже нетипові як здається. Звичайно переважна більшість їх зустрічається вже поза транзакційною областю застосування і відноситься до BI систем, але тим не менш досить поширена. Але всеж таки зустрічаються в складних документах, де платіжні інструкції включають в себе різнорівневі перевірки, ліміти, часові інструкції чи транспортні задачі. Це стосовно Українського ринку ПЗ. А от досвід міжнародний таку кількість випадків значно збільшує. Сподіваюсь тут є хтось з Укрсоцбанку і зможе розповісти про їх досвід (нажаль негативний) впровадження Temenos T24.

leopard.in.ua/…​/nosql-world#.WNJdIWmxVnE — 3.5 года назад написал статью на тему NoSQL, пока еще актуальна.

А де ж версiя солов’iною?

английский язык — язык международного общения. Учите :)

Спасибо автору за то, что благодаря комментариям к таким статьям понимаешь, что мы не только сыры и ЗП обсуждать «могём», но и работу работать умеем :)

Всегда интересно почитать раздел «Как работает реляционная база данных» в статье. Каждый раз открываешь для себя что-то новое :)

За труд всегда зеленка.
но пара комментов все же. Для меня некоторые выражения просто режут слух
1.

Каждая таблица — это один или более индексов (clustered and unclustered indexes)
Таблица это не всегда индекс. Heap/Hash ?
Что такое unclustered ? Может nonclustered ?

2.

Это значит, что, если у вас в таблице десять индексов, при каждой записи (удалении, вставке или изменении) в таблицу, база данных будет делать десять записей (минимум) на диск в b-trees.
Это совершенно не так. Определенный атрибут задействован в ключе каждого из 10 индексов и CRUID операция ссылаться на такой атрибут то — тогда действительно будет перестроены части BTree. Однако я с трудом представляю дизайн индексов где один и тот же атрибут использован повсеместно.
Если говорить об обновлении ключа кластерного индекса то опять же вопрос к дизайну физической схемы а не к SQL.

3.

Так как база поддерживает ACID — все операции с данными синхронные, а значит, придется ждать пока все операции записи будут завершены перед «коммитом» транзакции

Формулируйте мысль правильно. Этот процесс называется Write Ahead Logging.
Операции давно завершены перед комиттом. Как только сброситься лог в лог транзакций и придет подтверждение от IO тогда транзакция будет durable.
К слову в SQL SERVER давно (года 3 как) уже существуют отложенные транзакции.

4.

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

5.

Компромисс между чтением и записью можно обойти при помощи создания второй базы, которую называют Data Warehouse — ее оптимизируют под чтение данных и создание сложных отчетов.
Почему второй ? А если она третья ? Шутка.

Ee не оптимизирует под чтение. Этот процесс «иногда» называют денормализацией. И основная идея дать возможность бизнес пользователям иметь понятную схему для создания отчетов. Так было изначально...

6.

Другими словами, вы не можете транзакционно писать одновременно в Operational базу и в Data Warehouse — транзакция будет распределенной и очень медленной.
Впервые слышу за свою жизнь что такое может кому то придти в голову. DWH никогда небыли транзакционно консистенты и up to day c OLTP. Да и не в этом их цель собственно.

7.

P.S. На моей последней работе вообще нет SQL, и я считаю это приятным бонусом ко всему остальному.

И это правильный выбор !

Не мне судить но даже с теорией есть «небольшие» проблемы. Я бы рекомендовал прочесть что нибудь из разряда «Internals» для профессионалов.

Это значит, что, если у вас в таблице десять индексов, при каждой записи (удалении, вставке или изменении) в таблицу, база данных будет делать десять записей (минимум) на диск в b-trees.
Это совершенно не так.

если совсем точно, то в SQL Server это не так, но в других базах возможно. Например в PostgreSQL.

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

Может получиться так, что мы продадим немного больше товара, чем реально есть на складе
А теперь представьте, что так работает какой-нибудь booking.com: прилетаешь, скажем, в Тайланд, а в твоем номере кто-то живет...

Или Укрзализниця продает по 5 билетов на одно место. Авось кто опоздает или заболеет.

прикол что такое один раз было на моей памяти — продали 2 билета на одно место

Для авиакомпаний это стандартная практика перепродавать на 10-15% больше билетов, чем есть мест в самолёте.

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

В Европе такая практики уже запрещена.

Один и тот же отель часто представлен и на других сайтах помимо букинга. Хз как они разруливают.

У чувака на ресепшине открыто несколько вкладок в браузере.

А чувак транзакции поддерживает?)

Чувак все поддерживает. И еще успевает недостающие полотенца выдавать. :))))

К сожалению не могу найти ссылку на статью, но лет 8 назад именно так и было на booking.com (или hotels.com, но точно на одном из крупнейших).
Только связано это было с распределенным кластером, в котором нет транзакций, и
отказоустойчивостью каждого региона, что было куда важнее таких конфилктов в днных.
Когда такие конфилкты возникали, они решались именно вручную, предлагая постояльцу номер более высого класса либо другую гостинницу.

И чем это закончилось? Были ли довольны пользователи?

Статья была скорее технического плана, но раз такой гигант себе это позволял, значит репутационные/финансовые потери были значительно ниже невозможности самого брониварония.

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

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

PS вы осправиваете само существование eventual consistency как подхода? Или утверждаете, что продажи не та область применения?

Их системы это несколько датацентров в разных регионах мира и ни о каких распределенных транзакциях и речи быть не может.
Почему сразу не может? Сделать синхронизацию между инстансами хоть через Атланту — это чисто техническая задач и вполне решаемая, пусть и с небольшими задержками. Вопрос лишь в том, что важнее — скорость или надежность. Так что:
Или утверждаете, что продажи не та область применения?
Да, продажи и бронирования. Тем более, конкретных единиц товара/услуги (вроде определенного места в определенном поезде).
Например, мне как юзеру, например, все равно сколько транзакция займет времени — полсекунды или 15 секунд или даже минуту, когда я бронирую конкретный номер, который («УРА Я ТАКИ УСПЕЛ!») остался последний, с этим шикарным видом на море...

ЗЫ но бизнес не всегда выбирает в пользу интересов пользователя. Так и живем(

Почему сразу не может? Сделать синхронизацию между инстансами хоть через Атланту — это чисто техническая задач и вполне решаемая, пусть и с небольшими задержками.
Я могу ошибаться, но вполне возможно, что split brain между регионами (что довольно частая ситуация, по крайней мере на моей практике, AWS запада США теряет свой же регион во Франкфурте на пару минут почти каждую неделю) отчасти тоже влияет на выбор данного подхода. Лаг в несколько минут в современном бизнесе не допустим.
Например, мне как юзеру, например, все равно сколько транзакция займет времени — полсекунды или 15 секунд или даже минуту
Лично я с вами не могу согласится, если что-то долго работает, то скорее всего я сменю сервис. Как минимум, как показывают продукты, над которыми лично я работаю, скорость ответа является суть ли не найважнейщим параметром в современном мире.
Лаг в несколько минут в современном бизнесе не допустим.
Стабильный лаг в несколько минут в современном мире указывает или на большие проблемы с вычислительными ресурсами или на большие проблемы в архитектуре/имплементации системы. Обе проблемы решаются расширением инфраструктуры и оптимизацией/реинженирингом кода, соответственно. И дело тут никак не в консистентности транзакций.
если что-то долго работает, то скорее всего я сменю сервис
А я не могу согласиться, что все операции должны иметь одинаковые критерии скорости и надежности. Надо понимать, что разные операции могут иметь разные нефункциональные требования. Если страница с описанием товара в каком-нибудь интернет магазине будет грузиться минуту, я тоже скорее всего уйду на другой сайт. Но если после нажатия кнопки Купить, мне придется подождать лишние 15 секунд, пока транзакция обрабатывается, то это вполне терпимо для такой, относительно редкой, но важной операции.
P.S. На моей последней работе вообще нет SQL, и я считаю это приятным бонусом ко всему остальному.

Такое впечатление, что просто не любите SQL)
А как вы решаете задачи, которые просто реализуются реляционными СУБД? Например запрос, связывающий несколько источников данных по некоторому условию? Или обновление одного источника, если произошло изменение второго источника.

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

просто другая философия, приложение не прослойка между пользователем и базой, а база всего лишь резервная копия состояния чтобы программа не потеряла данные при сбое

Во-первых, я спрашивал не вас, а Антона.
А во-вторых, меня интересовал ответ на конкретные вопросы, а абстрактные рассуждения на тему NoSQL БД.

ну можно подождать пока Антон тоже напишет «никак, это не надо»

Вы сами то поняли, что написали?

предполагаешь что я «нет» могу написать?)

На самом деле, я просто спрашиваю) 3и раза пытался вникнуть в суть, но полное отсутствие группировки слов в предложения сильно затрудняют этот процесс...

я написал что если относится к базе только как к абстрактному хранилищу, то все ее реляционные плюсы теряются. апи упрощается с tsql до get/set по id и в итоге можно пользоваться любым хранилищем хоть в файл пиши вместо базы. есть другой подход. в нем проектируется база и связи в ней, а приложение выступает посредником между пользователем и базой. надеюсь так понятнее

О, так гораздо понятнее, спасибо) В целом, согласен. Но все таки «реляционные плюсы» полностью не теряются, даже если использовать БД чисто как хранилище. По моему опыту главный реляционный, т.с., плюс — это возможность композиции произвольных сложных структур данных из набора простых таблиц, что при грамотном дизайне приводит к компромиссу между занимаемой памятью и быстродействием. А использовать транзакционность или синхронизировать на уровне сервера — это уже вопрос дизайна конкретной системы.

Там все понятно, такие приложения существуют в реальности, хоть это и ужас, но всегда весело)

даже статья недавно была на доу об одном таком.

Имеется в виду статья «Построение кэша с эффективным многопоточным доступом»?
Там построение велосипедов отчасти оправдано. Я имею в виду приложения, которые строят в памяти эти вот object-relational маппинги, т.е. по сути, воссоздают объекты в процессе старта и потом работают с этими объектами. При этом с приложением работает 1 (адын) пользователь.

не, я имел ввиду dou.ua/…​a/columns/dont-use-rdbms
прицип работы там такой и есть, все данные юзера читаются просто из файла целиком в память по ключу и потом пишутся обратно на диск при необходимости, и да, я так понимаю никакой конкурентности, один объект на одного пользователя иначе два клиента будут затирать изменения друг друга при работе с одними и теми же данными.

Или обновление одного источника, если произошло изменение второго источника.

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

А как вы решаете задачи, которые просто реализуются реляционными СУБД? Например запрос, связывающий несколько источников данных по некоторому условию?
Ну задачи уровня — сделать запрос из нескольких источников данных можно решать по разному. Несколько источников данных на практике это несколько разных апи отдающие json или xml. Скорее всего это разные сервисы и они не могут быть полностью согласоваными (strict consistency). Мне кажется в зависимости от сложности и характера запросов лучше использовать документную базу или решения типа Spark

Azure Table наскільки я розумію є аналогом AWS DynamoDB яка в свою чергу є деяким аналогом Cassandra яка належить до Key-Column-Value Storage.
DynamoDB підтримує і Secondary Indexes і conditional writes і expiration time і ще кучу різних цікавих штук і для старту проекту як на мене — ідеальний варіант.

В Azure Table Storage нет Secondary Indexes, я раньше думал это проблема, но теперь я придерживаюсь мнения что это хорошо что так сделали by design. Если нужны индексы — у МС есть Azure DocumentDb, которая очень близка к MongoDb

Я бы автору посоветовал почитать книги о том как устроенные БД/СУБД и не нести кашу из разных понятий.

Я понял за годы работы программистом, что многие реальные бизнес-процессы не требуют строгой консистентности и транзакционности всех операций. Как пример — продажа товара в интернет-магазине. Представьте себе у вас есть 10 000 000 покемонов и весь мир потенциальных покупателей.
Вот после таких примеров потом кто-то из неокрепших умов будет писать какой-нибудь интернет магазин донорских органов, забив на консистентность и транзакционность...

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

С таким подходом, вы всех клиентов распугаете. Надо понимать, что многие бизнес-процессы требуют консистентности. Покупка товара — это один из таких процессов, например.
ТС пытается убрать консистентость там, где ей самое место, и принести в жертву непонятно чему... скорость? На кой юзеру скорость транзакции, если ему в стократ важнее, что бы транзакция была обработана гарантированно правильным образом?

Обычно скорость и eventual consistency работают для ускорения чтения. Вот при записи уже соблюдается консистентность при таком проектировании, где она действительно нужна. Просто у автора топика как-то в этой аналогии все вкуче он говорит про оптимизацию скорости транзакций, приводит пример optimistic concurrency и рассказывает про кеш базы для чтения.

Именно. Автор как раз и предлагает нарушить консистентность там, где она нужна.

Для вас будет большим отркровением когда вы узнаете как работает снятие денег с банкомата. И вообще банковские транзакции.

Заинтриговали! Просветите, плз.

Та шо там удивительного промисы в мире финансов появились на много раньше чем в программировании.

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

Примерно так?

В момент покупки/снятия сумма блокируется, а через несколько дней списывается. При конвертации валют это может привести к уходу счета в небольшой минус (на момент блокирования денег хватало, за 2 дня курс поменялся и по новому не хватает) Однако:
1) Если денег не хватает изначально — оплата/снятие не произойдут
2) Клиент сразу видит уменьшение денег на счету, как только происходит блокировка суммы.

С точки зрения клиента всё выглядит нормально, большинство никогда даже не будут знать как оно на самом деле происходит. В отличии от примера в статье, когда по факту товара нет, а интернет-магазин показывает что есть.

А я вспомнил: мелькала тут несколько месяцев назад статья с названием вроде «как я забыл SQL, и сэкономил кому-то там что-то там». Это вторая часть, да? )

В качестве доброго совета — не стоит вчитываться в статью и тратить своё время.
Утверждение автора, касательно реляционных БД, на котором основывается статья — не верно.
Автору — вариант совместного использования реляционных и не реляционных БД в больших проектах — часто приносит пользу. Но, полный отказ от реляционных БД — там же — вряд ли хорошая идея.

Все зависит от поставленной задачи
Ключевая фраза, с которой можно было начинать.

не знаю чем там занимается компания Bannerflow, но мне как клиенту не хотелось бы столкнуться с ее продуктами

Судя по названию, там связь с интернет-рекламой. Это, действительно, такая отрасль, где плюс-минус несколько процентов от показов и их учётов ничего не меняют, вплоть до того, что если учёт сломался, лучше продолжать показывать без учёта. Так что для этой ниши продукты могут быть вполне нормальными.
Главное — не пытаться переносить на другие направления.

Но это уже будет не наша проблема, а проблема директора (владельца), где достать больше товара. Обычно она решается пополнением склада или возвратом денег клиентам. Я вас уверяю, лучше иметь проблемы со сверхпродажами вместо проблемы с тормозами вашего интернет-магазина
Как покупатель негодую с такого подхода.

Угу, а всякие амазоны, ебеи и алиекспресы, контролирующие наличие на складах просто лохи не умеющие в бизнес..

Я вас уверяю, лучше иметь проблемы со сверхпродажами вместо проблемы с тормозами вашего интернет-магазина
С таким девизом можно новый тренинг по продажам открывать.
Я понял за годы работы программистом, что многие реальные бизнес-процессы не требуют строгой консистентности и транзакционности всех операций. Как пример — продажа товара в интернет-магазине
Это если магазин не заботится о своей репутации. Я один-два раза не смогу купить в интернет-магазине товар и поставлю его в черный список и другим рекомендовать не буду. И мне все равно, что они пожертвовали консистентностью в угоду скорости работы.

Хитрый магазин добавит фразу «Под заказ».

что в действительности означает «нету и не знаем когда будет» :-)
хитро-опый способ получить краткосрочный кредит

именно так), но когда покупатель против уходят за «у нас такой порядок». Далее следуют рассуждения на тему недобросовестных покупателей и т.п.

Какова вероятность того что из-за отсутствия поддержки транзакций в БД у вас дважды уведут товар «из-под носа»? Я думаю для среднего магазина она будет пренебрежимо мала.

я вчера (26 марта) делал заказ на Amazon. Добавил 4 айтема и уже перед оплатой вижу, что доставка будет не раньше 1го июня (!!). Одного из товаров, которые я положил в корзину, не было на складах Амазона. Методом исключения я убрал этот товар и сделал свой заказ.

Так вот скажите мне — у Амазона большие проблемы и им надо все переделать? Амазон скоро обанкротится и можно бежать продавать акции?

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

пол года назад мне амазон обещал доставить товар через 2 месяца. Через 2 месяца я получил сообщения «оббегали все склады, но ваш товар найти не смогли. Приймите наши извинения». (при этом карта не биллится, пока не произойдет шипмент) — я на Амазон конечно ругнулся, но покупать у них не перестал. Случается это редко.

Что там амазон — авиакомпании часто продают 105% билетов на рейс, тк есть у них статистика, сколько людей на рейс по итогу не приходит. Иногда случаются казусы, все приходят и кто-то злой остается на земле ждать след. рейса. Авиакомпании продолжают летать.

Это я к тому, что везде есть trade-off. Пока фича приносит больше профита, чем убытков от расстроенных клиентов — ее будут использовать.

Все задачи решать при помощи реляционной модели данных и SQL — плохая идея.
P.S. На моей последней работе вообще нет SQL, и я считаю это приятным бонусом ко всему остальному.

Само собою, в ТСа може бути дуже специфычний проект, але...

прочитав этот перл «Многие из них по-настоящему распределенные и масштабируемые горизонтально, в отличие от SQL.» задумался — то ли автор неграмотен в теме СУБД, то ли применяет прием маркетологов , подменяя понятия чтобы продать что-то

SQL — это язык запросов. он не может быть распределенным и масштабируемым.

и наличие PaaS и облачных хостингов никак не кореллирует ни с используемым языком запросов ни с типом СУБД
например тот же Azure использует диалект MS SQL

Автор в начале написал про использование SQL Server. Думаю, когда он в следующем абзаце написал просто SQL, то из контекста понятно, что имелось ввиду. В общем, не придирайтесь к словам. Имею ввиду, можно просто указать на неясность, а не обвинять автора в неграмотности.

Автор в начале написал про использование SQL Server.

«SQL Server» тоже не обязательно от MS.

А что плохого в SQL Server’е от MS?

Я не говорил, что в нём что-то плохое, и даже не намекал, поэтому Ваш вопрос неуместен. Но, если уж ответить, то в нём плохо то, что он 1) только для Windows, 2) чудовищно сложно и путано встроен в её конструкцию — Интернет заполнен жалобами, как для его работы ставится штук 15 разных сервисов, которые друг другу часто просто мешают. По сравнению с лёгкостью развёртывания и сопровождения, например, Firebird чи Postgresql, это отвращает.
(Тут можно долго оппонировать, что они все не содержат нужной конкретному оппоненту функциональности и вообще не кошерные, но мне это всё не актуально.)

1) только для Windows, 2) чудовищно сложно и путано встроен в её конструкцию
hub.docker.com/…​osoft/mssql-server-linux
Развертывается за 5 минут как и все остальное, о чем речь выше.

Да, слышал. Но слишком свежее, чтобы считать его рабочим. Всерьёз рассматривать — не раньше следующего года.

Это да, но тогда формулировка недостатков немного меняется. И звучит он так — я предпочитаю mature решения под linux/unix.
По поводу администрирования мс — он крайне прост и удобен. по поводу установки 15 разных сервисов тоже ерунда. не хотите olap или сервера отчетов — не ставьте.

я предпочитаю mature решения под linux/unix.

Mature должно быть по умолчанию. Unix (всех видов) — я высказал почти явно (как не-Windows).

По поводу администрирования мс — он крайне прост и удобен. по поводу установки 15 разных сервисов тоже ерунда.

Это были не мои утверждения, а высокоуровневых профессионалов MS SQL и администрирования Windows. Поэтому я предпочту таки верить им.
Контейнеризация тут, конечно, может всё упростить — хотя это радикальное решение :)

По первому пункту уже ответили, только добавлю, что это пока больше попробовать\поиграться, для продакшена пока не подходит

2) чудовищно сложно и путано встроен в её конструкцию — Интернет заполнен жалобами, как для его работы ставится штук 15 разных сервисов, которые друг другу часто просто мешают.

не стоит сравнивать пакет поставки MSSQL с Firebird или Postgresql. У MS вместе с СУБД идет вагон и маленькая тележка других продуктов и сервисов, в реальности на ПРОД серверах все сервисы не будут стоять на одной машине, а мешают они друг другу потому что люди при установке забивают делать нормальную конфугурацию сервисов, а просто жмут Next

Eventual Consistency решает проблемы с масштабированием
в книжці, на котру ви посилаєтесь, кажуть, що шардніг і реплікейшн вирішують цю проблему, а eventual consistency — це вже як наслідок.
много хранилищ данных на базе MapReduce
це ж просто модель для обробки даних, як це можу бути базою для збереження даних?

думаю автор имел ввиду что «база» в смысле «основа» а не в смысле "хранилище данных«—> тоесть «много хранилищ данных на основе [модели/алгоритма] MapReduce »,
где-то так

в книжці, на котру ви посилаєтесь, кажуть, що шардніг і реплікейшн вирішують цю проблему, а eventual consistency — це вже як наслідок.
Все правильно, они решают проблему. Но сделать шардинг и партишенинг на Оракле или SQL Server вам будет стоить очень дорого — enterprise лицензии и все такое.

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

Плюс. После прочтения этого раздела — дальше не читал

а что именно не точно или не правильно? единственно что вижу- это в том случаи если индекс один и он кластерный, то он храниться вместе с данными и его лишний раз апдейтить не надо. если же индексов больше — то всё так как написано в разделе

В основе реляционных баз данных лежит структура под названием b-tree, что накладывает определенные ограничения

Если я создам таблицу без индексов, то что в её основе будет лежать? Тем более такое чувство что кроме b-tree нельзя другие индексы использовать, как например r-tree, hash и прочее. У многих RDBMS индекс вообще отдельная структура.

с точки зрения реляционной теории таблица без индекса (без PK) не соответствует 1NF и на практике такая таблица встречатся очень редко . Практически каждая таблица содержит по одному индексу. r-tree, hash... скажите пожалуйста, а в каких СУБД можно создать индекс/таблицу в таких структурах?

r-tree, hash... скажите пожалуйста, а в каких СУБД можно создать индекс/таблицу в таких структурах?
Oracle, PostgreSQL, MySQL содержат r-tree и hash индексы
с точки зрения реляционной теории таблица без индекса (без PK) не соответствует 1NF и на практике такая таблица встречатся очень редко

Вопрос не в том, что такое встречается редко (и никто не запрещает существовать таким таблицам), а в том, что автор говорит, что

В основе реляционных баз данных лежит структура под названием b-tree

Хотя почему это стало основой для базы данных — не понятно.

> Если я создам таблицу без индексов, то что в её основе будет лежать?
Куча, она же heap.

Благодарю, я в курсе :) А вот у автора в основе лежит b-tree.

А не важливо, як працює, сказано же — «не підходить» :)
coub.com/view/591to

Ну так напишите альтернативную точку зрения. Я смотрю вы часто создаете в базе кучи и r-tree, расскажите нам об этом, очень интересно. Расскажите нам как часто вы создаете таблицы без индексов и для каких целей, заранее спасибо

Вы пытаетесь вести дискуссию на тему, в которой не ориентируетесь.
Кстати, насчет commit в ACID вы тоже не правы. Он, конечно, синхронный, но не в том смысле и не так страшно, как вы пишете.

Слив засчитан

Те же ACID транзакции не последовательны, изучите понятия «изоляция транзакций». Самая интересная реализация (на мой взгляд) в ORCL, где за счет версионирования данных можно снижать уровень изоляции, не нарушая целостность данных при параллельной работе.

Сами таблицы не имеют вообще никакого отношения в b-tree, хоть эта структура и встречается довольно часто в РСУБД. Данные таблицы лежат с страницах от 4кб и более (обычно привязано к размеру страницы самой дисковой подсистемы), где каждая строка это последовательность колонок, где одна страница имеет ссылку на другую страницу и тп. Пример на задуматься: почему запрос, содержащий OFFSET 153_000_000_000 работает медленно, а запрос WHERE ID > 153_000_000_000 при налиции индекса быстро?

Не нужно путать SQL язык и сами СУБД. Иначе получается, что тот же RedShift или Vertica это обычные реляционные хранилища.

P.S. На моей последней работе вообще нет SQL,
Скорее говорит о том, что у вас нет ни BI аналитики, ни связных данных с разным жизненным циклом.

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

Вот пожалуйста Оракл пишет

B-trees, short for balanced trees, are the most common type of database index. A B-tree index is an ordered list of values divided into ranges. By associating a key with a row or range of rows, B-trees provide excellent retrieval performance for a wide range of queries, including exact match and range searches.

По поводу аналитики лол. Мы используем Spark и Druid, а также сервисы Azure.

Классно Оракл гонит. Начнём с того, что все конкретные расшифровки буквы B — позднейшие городские легенды, и если как-то это хоть немного осмысленно расшифровывать, то Bayer tree — по имени основного изобретателя. Далее, все эти рассказы про ranges это только самый нижний уровень дерева (хоть и подавляющий).
Ну а что факт использования B-дерева для индекса сейчас — никак не соотносится с сутью RDBMS — уже сказали тут много раз.

Так а что конкретно не так? Это ж сбалансированное дерево, не? «Все эти рассказы про ranges» — тоже непонятно, в чем тут неправда? Предикат вида «some_column between one_value and another_value» вполне может быть преобразован в IRS на уровне плана, что тут неправдивого?

это только самый нижний уровень дерева (хоть и подавляющий)
Можете прояснить, что имеется в виду?
Это ж сбалансированное дерево, не?

При том, что к тому моменту AVL-дерево уже стало классикой и баяном, и были и другие попытки — ничего нового «сбалансированного» в B-дереве не было. И отличать его по этому признаку не было смысла.

А вот то, что в нём полезно — оптимизация работы с диском или другим медленным хранилищем за счёт страничной группировки — в слове balanced не отражено, от слова «никак».

Наконец, процитирую Википедию: [q]The origin of «B-tree» has never been explained by the authors. As we shall see, «balanced,» «broad,» or «bushy» might apply. Others suggest that the «B» stands for Boeing. Because of his contributions, however, it seems appropriate to think of B-trees as «Bayer»-trees. (Comer 1979, p. 123 footnote 1)[/q]

И дальше от второго автора: [q]B is, you know... We were working for Boeing at the time, we couldn’t use the name without talking to lawyers. So, there is a B. It has to do with balance, another B. Bayer was the senior author, who did have several years older than I am and had many more publications than I did. So there is another B.[/q]

Как видите, ничего общего с рекламными домыслами Оракла. (Впрочем, я им не удивляюсь — зачем им рекламировать Boeing и Байера?)

Для указания их отличий от AVL, red-black и прочих — broad и bushy значительно осмысленнее. Или таки по первому автору.

Можете прояснить, что имеется в виду?

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

С моей точки зрения, такая вот «научно-популярщина», которая является рекламной пропагандой, но маскируется под техническое описание, значительно хуже, чем само по себе техническое описание или реклама. И уж тем более не надо использовать такие гибридные агитки в технической дискуссии.

Предикат вида «some_column between one_value and another_value» вполне может быть преобразован в IRS на уровне плана, что тут неправдивого?

Против этого у меня не было никаких возражений, и не понимаю, чему Вы тут удивляетесь. Безусловно может быть преобразован, и это обычно делается. Более того, отсутствие таких возможностей во многих NoSQL движках ой не красит их и сильно сокращает их возможности (извините, я однажды неприятно наступил на эту граблю, теперь стараюсь ворчать об этом по любому поводу).

Для указания их отличий от AVL, red-black и прочих — broad и bushy значительно осмысленнее. Или таки по первому автору.
Ну тогда уже B+, но вообще какая разница? Картинка в документации проясняет структуру, а этого достаточно для большинства применений.
Если бы Вы проанализировали структуру B-дерева, заметили бы, что последовательные ключи там только на листовых страницах. Все страницы других уровней имеют заметные промежутки между ключами.

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

Это не мешает практическому эффекту, что подавляющее большинство диапазонных запросов таки редуцируется до листовых страниц и получает там достаточно эффективности за счёт пространственной локальности, но формально это не становится верным.
Этого я вообще не понял.
Что есть «пространственная локальность»? Листьевые блоки не обязаны быть рядом на диске или в структурах памяти, именно поэтому полный просмотр таблицы чаще намного эффективней доступа по индексу, но поскольку они объединены в двухсвязный список, сканирование индекса связано с получением начального блока (а это несколько дополнительных логических чтений так как высота дерева редко бывает больше 4, а обычно 2-3) и дальше проходом по списку.
Ну тогда уже B+,

С чего вдруг? B⁺ это уже для кластерного индекса, а для других (где рядом с ключом только ссылка на адрес записи или на primary ключ) — просто B.

но вообще какая разница? Картинка в документации проясняет структуру,

Пусть проясняет — я говорил исключительно о нездоровой фантазии оракловских менеджеров в плане расшифровки того, что не расшифровывается, под их вкусы.

а дальше читаются только листовые блоки, я не понимаю о чем Вы говорите.

Это только по одной из реализаций (вообще же их у B-деревьев за счёт гибкости общей концепции — как собак нерезаных). Мне не интересно в таких деталях, что там конкретно у оракла. Ну ладно, поверим (тогда, опять же, эти все рассказы касаются только их реализации, а не общей схемы — ещё один «незачёт» авторам агитки).

Этого я вообще не понял. Что есть «пространственная локальность»? Листьевые блоки не обязаны быть рядом на диске или в структурах памяти,

Локальность в пределах одного блока (что для диска критично, а для RAM просто полезно). Это всё в контексте, что именно в B-деревьях было принципиально новым, в отличие от прежних идей.

С чего вдруг? B⁺ это уже для кластерного индекса, а для других (где рядом с ключом только ссылка на адрес записи или на primary ключ) — просто B.
Нет, B+ — это стандартная структура индекса для многих РСУБД. Кластерный индекс тут ни при чем. Ссылка на первичный ключ в индексе не имеет смысла для обычных индексов.
Пусть проясняет — я говорил исключительно о нездоровой фантазии оракловских менеджеров в плане расшифровки того, что не расшифровывается, под их вкусы.
Претензия все равно непонятна, структура объясняется, картинка есть, даже примеры)
Локальность в пределах одного блока (что для диска критично, а для RAM просто полезно).
Так это, в пределах одного блока целая куча пар ключ-адрес строки)
Это все, собственно говоря, можно узнать из документации.
Так это, в пределах одного блока целая куча пар ключ-адрес строки) Это все, собственно говоря, можно узнать из документации.

OK. Я так уже и понял, что для Вас эта документация это некое священное писание, на которое Вы ссылаетесь, даже если никто не просит ответа по этому поводу. Не относясь к религии поклонников книг Oracle, я предпочту остановить обсуждение тут.

Чего обижаться-то? Документация конкретно по DBMS у Оракла более-менее, хотя бы потому что имеет многолетнюю историю и за это время куча ошибок было исправлено и сама документация постоянно шлифовалась. Во многих продуктах чтение документации само по себе не добавляет понимания, особенно меня поразили в этом плане некоторые айбиэмовские продукты. Здесь достаточно просто почитать, просветление наступает сразу. Если продолжать фантазировать на тему абстрактных структур данных и различных вариантов деревьев, то отсюда как раз и появляются всякие городские легенды.

Чего обижаться-то?

Не знаю, я не обижаюсь.

Документация конкретно по DBMS у Оракла более-менее

Документация — может быть. Агитки — нет. Сам софт, вообще-то — тоже не торт и не фонтан. Как мы боролись с deadlockʼами в многонитевом OCI — можно было мини-сагу писать, нашли ещё штук 30 якобы исправленных багов на ту же тему, и я не думаю, что сейчас что-то фатально исправилось. Просто не надо брать один источник за священное писание.

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

Это не фантазии, а голая реальность — для тех, кто работал более чем с одной СУБД. Вероятно, Вам это ещё предстоит.

Как мы боролись с deadlockʼами в многонитевом OCI — можно было мини-сагу писать, нашли ещё штук 30 якобы исправленных багов на ту же тему, и я не думаю, что сейчас что-то фатально исправилось.
А можете написать номер бага или примерное описание проблемы?
Это не фантазии, а голая реальность — для тех, кто работал более чем с одной СУБД. Вероятно, Вам это ещё предстоит.
Ага, ок. В каких конкретно СУБД используется не B+ реализация? То есть, в каких СУБД не только в листьевых блоках содержатся пары ключ-адрес строки в таблице?
А можете написать номер бага или примерное описание проблемы?

Номер бага — не могу, но думаю, что любой оракловый DBA с доступом к их трекеру запросто найдёт.
Описание — произвольные дедлоки при использовании доступа к OCI одновременно из нескольких тредов (там режим, когда пул коннектов используется пулом тредов — проблемы были именно в нём). Наш DBA-с-доступом находил около 20 таких багов в истории, после того, как мы наивно применили эту фишку и получили блокирования на ровном месте.

(ИЧСХ, трейсы в живом процессе содержали множество имён функций вида isckpa0(), что меня никак не радовало в плане качества поддержки этого OCI самим Ораклом.)

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

Ещё что тогда «радовало» — пришлось пачки мелких операций склеивать в одну транзакцию просто потому, что иначе оракл перегружался этими частыми транзакциями. DBA тогда бегал и вправлял на эту тему мозги всем; биллингу было проще, у них обычно операции крупные, а у нас в SIP было много мелких, и мы создавали ему жуткую головную боль.

В каких конкретно СУБД используется не B+ реализация?

В современных — вероятно, уже нигде (из семейства B).

Насчёт «предстоит» возьму назад — с нынешним прогрессом, скорее всего, уже если будет изменение, то в сторону каких-то совсем других технологий.

Описание — произвольные дедлоки при использовании доступа к OCI одновременно из нескольких тредов (там режим, когда пул коннектов используется пулом тредов — проблемы были именно в нём). Наш DBA-с-доступом находил около 20 таких багов в истории, после того, как мы наивно применили эту фишку и получили блокирования на ровном месте.
(ИЧСХ, трейсы в живом процессе содержали множество имён функций вида isckpa0(), что меня никак не радовало в плане качества поддержки этого OCI самим Ораклом.)
Ничего непонятно. Поиск по функции ничего не дает ни на металинке, ни в гугле. Как связаны дедлоки (если имеются в виду именно дедлоки на табличном уровне ака ORA-60) с режимом подключения типа dedicated or shared, тоже непонятно.
Ещё что тогда «радовало» — пришлось пачки мелких операций склеивать в одну транзакцию просто потому, что иначе оракл перегружался этими частыми транзакциями.
Ну это проблема для всех СУБД, где поддерживается WAL. Синхронизация записи в журнал и/или сброс журнальной информации в файл(ы) становится узким местом рано или поздно.
Поиск по функции

По какой именно?

если имеются в виду именно дедлоки на табличном уровне

Это как же можно было так прочитать? ;)
Дедлоки на структурах OCI клиента в приложении, которое коннектится к базе.

Ну это проблема для всех СУБД, где поддерживается WAL.

Но почему-то на InnoDB в MySQL, который был первым в эксплуатации движком, ничего подобного не происходило. Или там WAL некошерный? :)

По функции

isckpa0
Дедлоки на структурах OCI клиента в приложении, которое коннектится к базе.
Ничего не могу сказать, последний раз сталкивался с OCI-ными библиотеками лет 10 назад наверно. Но интересно было бы понять, о какой проблеме идет речь. Из описания ни фига непонятно, к сожалению.
Но почему-то на InnoDB в MySQL, который был первым в эксплуатации движком, ничего подобного не происходило. Или там WAL некошерный? :)
Но почему-то использовали Oracle, a не MySQL.
И шо, тогда на InnoDB таки было много-много транзакций тогда?
Из описания ни фига непонятно, к сожалению.

Гм, думаю, это уже не моя вина. Я описал три раза разными словами.

Но почему-то использовали Oracle, a не MySQL.

Желание толстых заказчиков.

И шо, тогда на InnoDB таки было много-много транзакций тогда?

Получалось около 100 в секунду, насколько я помню. Ораклу это было на пределе. Да, мало, но это была небольшая стендовая установка (типичный нормальный сервер 2010 года). MySQL и в 10 раз больше спокойно переваривал на идентичных железе и ОС. Не думаю, что дело было в недотюнинге — DBA и так скрутил всё, что смог.
Подчеркну, что вопрос не в абсолютных цифрах, а в том, что WAL не аргумент, если можно получить десятикратную разницу производительности.

Гм, думаю, это уже не моя вина. Я описал три раза разными словами.
OK) интересно было посмотреть что за проблема, но нет так нет.
Получалось около 100 в секунду, насколько я помню. Ораклу это было на пределе.
Ну это вообще не смешно. Никаким пределом тут и не пахнет, для любой системы.
Подчеркну, что вопрос не в абсолютных цифрах, а в том, что WAL не аргумент, если можно получить десятикратную разницу производительности.
На этом мы завершим беспредметный спор. Сначала речь шла о том что мелкие и частые транзакции нужно заворачивать в более крупные, и это правильно, так как логично что это облегчает жизнь любому компоненту, который пишет информацию в журналы, так как для этого компонента важна синхронность записи для возможности восстановиться потом в случае сбоя, а дальше пошла уже какая-то новая городская легенда о том, что 100 транзакций в секунду — это предел для Оракла в 2010 и MySQL (на InnoDB, я так понимаю)
в 10 раз больше спокойно переваривал на идентичных железе и ОС.
Ничуть не спорю о том, что на MySQL можно получить лучшую производительность на определенных RW-операциях, но аж никак не 10х.

Простите, но я не понимаю к какому конкретно месту моего комментария ваш ответ относится.

B-trees, short for balanced trees, are the most common type of database index
обратите внимание на слово «index», которое не имеет никакого отношения к хранению самих данных в БД. И да, добльшинство РСУБД имеют файловую систему в виде «кучи», хотя такое наименование и встречается довольно редко. Таблицы без индексов это тоже норма, используются в ежедневном обиходе.
MongoDb выигрывает в производительности записи у SQL
не пишите, пожалуйста, такие вещи. SQL это язык, ваш любимый SPARK тоже имеет свою реализацию SQL. Тот же Couchbase имеет свой SQL подобный N1QL. Пожалуйста, пользуйстесь правильной терминологией. Второе: само утверждение крайне не корректно, пусть и правдиво для некоторых задач. Ваш же текст утверждает о всеоблемящей более высокой производительности Mongo на MySQL, что не верно (первый же линк из поисковой выдачи stackoverflow.com/…​sql-vs-mongodb-1000-reads). Из моей практики жечь балк аплоадом на ec2.medium инстансе можно со скоростью по 100к записей в секунду даже не прибегая к тюнингу самого сервиса MySQL.
По поводу аналитики лол.
«BI» аналитики, не пропускайте слова, пожалуйста. Вы только больше убедили меня в корректности моих выводов, спасибо.
SQL> select count(*) from dba_tables dt where not exists (select null from dba_indexes where table_name = dt.table_name);

  COUNT(*)
----------
       458

SQL> select distinct index_type from dba_indexes;

INDEX_TYPE
---------------------------
IOT - TOP
FUNCTION-BASED DOMAIN
LOB
FUNCTION-BASED NORMAL
BITMAP
NORMAL
CLUSTER

7 rows selected.

В упомянутых вами Data Warehouse до половины таблиц может быть без индексов и ключей. В staging area. И это бест практис. Знаете почему ?

Нет не знаю, я не эксперт в Data Warehouse. Расскажите, очень интересно.

Staging area/Landing/ODS — грубо говоря схема временных таблиц используемые ETL (и не только) для быстрой (bulk load) загрузки данных. Часто здесь включен Data Quality поскольку данные сырые и часто отображают дельту изменений OLTP.
Так вот для такой нагрузки индексы/ключи/триггеры как раз не рекомендованы.
Например посмотрите на дизайн таблиц technet.microsoft.com/…​/dd537533(v=sql.100).aspx

Всю статью можно было уместить в

Все зависит от поставленной задачи. Все задачи решать при помощи реляционной модели данных и SQL — плохая идея.

А вот это выглядит как будто автор комплексует по этому поводу

P.S. На моей последней работе вообще нет SQL, и я считаю это приятным бонусом ко всему остальному.

Подписаться на комментарии