Чи не час реляційних баз даних на звалище історії, savepearlharbor

Здравствуйте, меня зовут Дмитро Карлівський і я ... антіконформіст, тобто людина, яка не тримається за свої звички і завжди готовий їх поміняти, якщо в цьому є необхідність. Наприклад, як і багато розробників, я починав вивчення баз даних з реляційних. Хоча реляційна алгебра і досить красива в своїй простоті, я постійно ловив себе на думці, що намагаюся впихнути круглу фігуру в квадратний отвір і виходило якось не герметично 🙂







Ні, я не буду розповідати вам про MongoDB або ще якусь неповноцінну «вбивцю SQL». Статей на тему «SQL vs NoSQL» порівнюють насправді реляційні СУБД з документні і так повно:

  • Популярність: Oracle, MongoDB, Redis, HBase, OrientDB.
  • Функціональність: OrientDB, Oracle, MongoDB, HBase, Redis.
  • Швидкість: дуже сильно залежить від завдання, даних і реалізації програми. Я переглянув купу бенчмарков, всюди все по різному.

Сили тисяч розробників спрямовані на те, щоб досить прості моделі предметної області розташувати в табличках так, щоб це було швидко, гнучко і не дуже складно. Виходить погано. Пишуться величезні ORM фреймворки, зубодробильні SQL запити, створюються величезні індекси, і дублюються дані.

Ось, скільки статей на одному тільки Хабре написано про проблему, яка є виключно в РСУБД зважаючи спроби упіхнуть все різноманіття моделей предметної області в прямокутні таблиці:

Всі рішення зводяться до трьох основних:

Таблиця суміжності. Нащадок зберігає посилання на батька. Тут не зберігається порядок нащадків (щоб його зберігати потрібно вводити додаткову нумерацію, по якій сортувати, що уповільнює як вставки так і вибірки). Потрібні рекурсивні запити або денормализация таблиць смежностей.

Рекурсивний запит поддерева:

Запит поддерева по денормалізованной таблиці суміжності:

Матеріалізований шлях. Нащадок зберігає номери всіх предків (зі збереженням їх порядку). У гіршому випадку зміна ієрархії призводить до оновлення даних всіх вузлів. При відсутності відповідного АПИ з боку СУБД, вимагає фігурної маніпуляції над рядками, що не у всіх випадках прийнятно за швидкістю. Не допускає входження одного нащадка в кілька предків.

Запит поддерева з використанням ordpath:

Вкладені інтервали. Кожен вузол зберігає два числа, які визначають його точне положення в ієрархії. У гіршому випадку зміна ієрархії призводить до оновлення даних всіх вузлів. Не допускає входження одного нащадка в кілька предків. Щодо складні алгоритми вимагають підвищеної акуратності.

Як бачимо, кожен тип рішення має свої серйозні обмеження на представимо їм модель і ефективність різних типів запитів. А знаєте чому немає такого великого числа ґрунтовних статей про зберігання дерев, наприклад, в графових СУБД? Та тому, що там в принципі немає цих проблем, так як дерево - це окремий випадок графа. Так що питання «як же мені так примудритися і зберегти в базу ієрархію» в графових базах взагалі не варто.

Запит поддерева в графі:

Так, нереляційні СУБД, не дивлячись на загальну назву «NoSQL», теж можуть підтримувати Structured Query Language, розширюючи його своїми операторами 🙂

Багато SQL-профі тут зазвичай заявляють, мовляв дерева і тим більше графи в предметних областях майже не зустрічаються. Але варто трохи вийти із зони комфорту як тут же побачиш, що будь-яка предметна область насправді представляє з себе граф - набір сутностей, між якими є різноманітні відносини. Якщо відносини ці 1-к-1 або хоча б 1-ко-многим і при цьому пов'язують лише різнотипні суті, то такі моделі відносно легко лягають на реляційну модель (якщо не враховувати різні види Джойна з милицями у вигляді індексів). Але зазвичай все не так. У багатьох місцях можна зустріти відносини багато-до-багатьох. У РСУБД для кожного такого ставлення доводиться заводити окрему таблицю і кілька індексів до неї, а це ускладнення архітектури, роздування даних і уповільнення роботи з ними.

Деякі, особливо «передові» програмісти, пропонують зберігати кожен тип моделей у своїй СУБД. «Важливі дані» в реляційних, дерева в графових, а примітивні взагалі в словниках. Але подібні підходи виду «всякої задачі свій інструмент» лише додають головного болю (і як наслідок багів різного ступеня тяжкості) на тему консистентності даних в різних частинах програми.







Програмна розробка - штука дуже динамічна. Сьогодні майстер у вас повинен мати одну професію і ви просто даєте йому текстове поле вписати її. Завтра буде потрібно, щоб він міг вказати професію лише із запропонованих вами і ви даєте йому селект для вибору потрібної, зберігаючи id професії в модель майстра (один-ко-многим). Після завтра буде потрібно, щоб він міг вибрати кілька професій разом (багато-до-багатьох). А через тиждень вам терміново потрібно реалізувати вже ієрархічний каталог професій. У реляційної СУБД складність кожного наступного переходу значно перевершує попередній. З графовой - ви більше часу витратите на обговорення, ніж на реалізацію. Так що при старті проекту має сенс брати найбільш гнучкий інструмент, який дозволить вам не втрачати темп розробки в процесі зміни бізнес вимог (або кращого розуміння оних). Так, спеціалізовані інструменти можуть в деяких випадках бути швидше і саме в цих випадках, якщо в цьому є необхідність. варто займатися такого роду оптимізацією.

Часто тлумачні SQL-розробники беруть якусь MongoDB, про яку говорять на кожному розі, і намагаються приміряти до свого проекту, але розібравшись з нею, не розуміючи, крутять пальцем біля скроні. Безглузді так і залишаються на MongoDB, мириться з відсутністю транзакцій і відносин між документами, заради міфічної швидкості і можливості засунути в документ будь-якої json.

Давайте розвіємо кілька типових міфів з приводу NoSQL, про який судять по найбільш гучним представникам - MongoDB і Redis:

1. Вони не контролюють структуру записуваних користувачем даних. У відсутності схем є і плюси (можна робити міграції даних у фоновому режимі, можна зберігати не тільки кортежі примітивів), але і мінуси (потрібно уважно стежити що записуєш в базу, неефективне зберігаються дані). У OrientDB знайшли розумний компроміс: ви можете вказати схему і зазначені там поля будуть затверджувати відповідно до неї під час запису і не будуть витрачати місце на імена полів, а не зазначені валідованого не будуть, але будуть займати трохи більше місця. Тут важливо зазначити, що зміна схеми не призводить до зміни самих документів - просто ви не зможете змінити їх поки не приведете до нового формату.

2. Вони не задовольняють вимогам ACID (Атомарність, Узгодженість, Ізольованість, Надійність). OrientDB цим вимогам задовольняє. Більш того, вона з коробки вміє партіцірованіе і майстер-майстер реплікацію, так що підтримує в тому числі і розподілені транзакції. При цьому ви можете регулювати баланс між узгодженістю і швидкістю відповіді:
writeQuorum визначає число вузлів, які повинні підтвердити запис, перш ніж СУБД поверне відповідь, про успішне завершення транзакції.
readQuorum визначає число вузлів, які повинні підтвердити актуальність даних, перш ніж дані повернуться у відповідь на запит.
За замовчуванням всі транзакції синхронні (чекаємо відповіді всіх реплік), а читання відповідно відбувається без підтвердження актуальності (за її не потребою в цьому випадку).
Примітною особливістю є прозора підтримка map-reduce: якщо вузол містить не всі дані, то він сам робить запит до решти вузлів і зливає їх відповіді. Клієнт може працювати з партіцірованной базою даних як з цілісною. Є навіть автобалансіровщік, розкидає документи в кластери за різними стратегіями.

Для порівняння підходів роботи з графовой і реляційної СУБД, давайте створимо просту бізнес сутність - персону:

Тут все просто і майже однаково. Тепер додамо відношення «друзі»:

Недоліки РСУБД вже починають вилазити - нам потрібна була додаткова таблиця і унікальний індекс на ній. Індекс цей з одного боку гарантує, що у нас не буде дублікатів зв'язків, а з іншого дозволяє швидко знаходити друзів за ідентифікатором користувача.

Виведемо основні дані про друзів одного з користувачів:

У РСУБД ми не можемо зберігати посилання між записами - тільки їх ідентифікатори. Тому з'являється хитра конструкція, яка пояснює як дані з однієї таблиці співвідносяться з іншого. У графовой ж ми просто розгортаємо посилання.

А тепер знайдемо друзів його друзів:

У РСУБД запит помітно ускладнився. По хорошому його потрібно ускладнити ще сильніше, щоб дані друзів першого рівня не дублювалися для кожного друга другого рівня.

Продовжувати можна довго, але суть, я думаю, вже зрозуміла. Трохи більше подробиць про відмінності реляційного підходу і графового можна почерпнути з презентації "How Graph Databases started the Multi Model revolution".

На останок зазначу, що в реляційних базах дані зберігаються таблицями, але вони вкрай неефективні при запитах, тому до них додають автогенеріруемое дерево - індекс. Причому індекси намагаються робити покривають, тобто не вимагають звернення до власне таблиць за даними. Так ось, якщо вирізати таблиці і дозволити індексному дереву мати цикли, то ми отримаємо ні що інше як графову СУБД, де вся база даних - це один великий максимально ефективний індекс.

Досить теорії. Що на практиці-то?

Останній рік я займався розробкою бекенд для проекту SKEDDY (Пошук майстрів і запис до них на послуги). Звучить начебто не складно, проте число бізнес сутностей зараз вже дорівнює 20 (20 таблиць сутностей, якби я використовував РСУБД): person, mail, phone, social, token, application, profession, service, meeting, assessment, album, image, notification, place, track, payment, article, aspect, facet, salon.

Завдяки графовой моделі даних, відображення на неї бізнес моделі відбувається легко і просто - один раз написаний простою узагальнений код для синхронізації з базою даних, дозволив програмувати в термінах бізнес сутностей без зайвих турбот про оптимізацію запитів до СУБД. Власне боротьба з AngularJS відняла куди більше часу, але це вже зовсім інша історія ...

Тепер про недоліки:

Документація досить не погана для основного функціоналу, але деякі аспекти в ній відображені вкрай слабо. Наприклад, інформацію про хуках доводиться збирати по крупицях.

Більше щось на розум нічого не приходить 🙂

PS: Мене можна захантіть в Пітері бо SKEDDY так і не злетів 🙂

Тільки зареєстровані користувачі можуть брати участь в опитуванні. Увійдіть. будь ласка.