Доступ до даних - що ж таке бази даних документів

Спочатку я повинна дати визначення NoSQL. Цей термін став занадто часто використовуватися. Їм узагальнено називають механізми зберігання даних, які не є реляційними і тому не вимагають застосування SQL для доступу до своїх даних. У статті «Addressing the NoSQL Criticism» (bit.ly/rkphh0) Бредлі Холт (Bradley Holt), експерт по CouchDB, згадує, що він чув, як деякі однойменні NoSQL як «не тільки SQL (not only SQL)». Його точка зору полягає в тому, що NoSQL ні в якому разі не слід розглядати як рух проти SQL. Ця думка мені до душі, тому що я вважаю за краще використовувати для конкретної роботи найкращі інструменти.

З безлічі доступних баз даних документів я зосереджуся на двох найбільш популярних - MongoDB (mongodb.org) і CouchDB (couchdb.apache.org), а також на RavenDB (ravendb.net), яка була написана для Microsoft .NET Framework і завойовує все більшої популярності (див. статтю «Вбудовування RavenDB в додаток ASP.NET MVC 3» в цьому номері). Всі деталі цих баз даних ви можете дізнатися, відвідавши їх веб-сайти.

Альтернатива реляційних баз даних, а не заміна

NoSQL і бази даних документів - це альтернатива реляційних баз даних, а не їх заміна. У кожної з них своя ніша, і вони просто розширюють коло вашого вибору. Але як вибрати потрібний? Важливий критерій - теорема узгодженості, доступності та відмовостійкості розділів (Consistency, Availability and Partition Tolerance, CAP). Вона стверджує, що при роботі в розподілених системах можна отримати тільки дві з трьох гарантій (C, A або P), тому ви повинні вирішити, що для вас важливіше. Якщо найважливіше узгодженість, тоді потрібно використовувати реляційну базу даних.

Приклад того, де узгодженість була б найважливішою гарантією, - банківський додаток або, можливо, додаток, що виконується на атомній електростанції. У таких сценаріях критично важливо враховувати кожну порцію даних в кожен момент. Якщо хтось знімає гроші з рахунку, вам дійсно потрібно знати про це, коли ви дивитеся на баланс його рахунку. Отже, ви швидше за все віддасте перевагу реляційну базу даних з високим рівнем контролю над її транзакціями.

Термін, який ви будете часто чути, - «кінцева узгодженість» (eventual consistency) або, як виражено на сайті RavenDB: «Краще застарілі дані, ніж автономні». У ряді предметних областей досить кінцевої узгодженості. Там не страшно, якщо видобувні дані не є актуальними з точністю до мілісекунди.

У якихось ситуаціях, можливо, важливіше існуванняякоїсь версії даних, а не очікування фіксації всіх транзакцій. Це відноситься до доступності (A) в CAP, що головним чином пов'язане з підтримкою безперебійної роботи сервера. Впевненість в тому, що ви завжди можете звернутися до бази даних, приоритетнее, і це дозволяє значно прискорити роботу бази даних (т. Е. Бази даних документів працюють швидко!). Ви побачите, що відмовостійкість розділів (P) теж важлива для баз даних документів, особливо при горизонтальному масштабуванні.

RESTful HTTP API - здебільшого

Багато з баз даних NoSQL доступні в стилі RESTful, тому ви встановлюєте з'єднання з вашою базою даних по URI, а запити і команди передаєте як HTTP-виклики. Винятком є ​​MongoDB. За умовчанням вона використовує TCP для взаємодій з базою даних, хоча доступний мінімум один HTTP API. CouchDB і MongoDB надають специфічні для конкретних мов API, які дозволяють писати і виконувати запити та оновлення для своєї мови, обходячись без кодування HTTP-викликів. У RavenDB є API .NET-клієнта, який спрощує взаємодію з базою даних.

Пов'язані дані в одному записі

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

Нижче наведено типовий приклад того, як може виглядати запис в базі даних документів (я запозичила цей приклад зі студентом з підручника по MongoDB):

унікальні ключі

Ключі потрібні в будь-якій базі даних. Якщо ви не надаєте їх, вони створюються за вас на внутрішньому рівні. Без ключів неможлива індексація баз даних, але у вашій предметної області можуть знадобитися відомі ключі (known keys). Зверніть увагу в попередньому прикладі з публікацією в блозі на посилання на «users / 203907». Саме так RavenDB використовує значення ключів і дозволяє визначати взаємозв'язку між документами.

Сховище в форматі JSON

Загальне у всіх цих записах-прикладах - вони використовують JSON для зберігання даних. CouchDB і RavenDB (і багато інших) зберігають свої дані в JSON. MongoDB використовує різновид JSON під назвою Binary JSON (BSON), яка дозволяє виконувати двійкову сериализацию. BSON - це внутрішнє уявлення даних, тому, з точки зору програмування, ніякої різниці бути не повинно.

Простота JSON полегшує перетворення об'єктних структур майже будь-якої мови в формат JSON. Тому ви можете визначити об'єкти в своєму додатку і зберігати їх безпосередньо в базі даних. Це позбавляє розробників від необхідності використання ORM (object-relational mapper) для постійної трансляції між схемою бази даних і схемою класів / об'єктів.

Механізми повнотекстового пошуку, наприклад Lucene (lucene.apache.org), на який спирається RavenDB, забезпечують високошвидкісний пошук в цих текстових даних.

Зверніть увагу на дату в прикладі з публікацією в блозі. У JSON немає типу, що підтримує дати, але кожна база даних надає спосіб інтерпретації типів date з будь-якої мови, на якому ви кодуєте. Якщо ви вивчите список Data Types and Conventions для MongoDB BSON API (bit.ly/o87Gnx), то побачите, що в нього доданий тип date поряд з кількома іншими.

Зберігання та отримання пов'язаних даних, що знаходяться в одному записі, може дати величезні переваги в продуктивності і масштабованості. Баз даних в цьому випадку не доводиться перелопачувати всю інформацію в пошуках пов'язаних даних, тому що всі вони зберігаються в одному місці.

набори типів

Звідки ваш додаток дізнається при взаємодії з базою даних, що один елемент є студентом, інший - книгою, а третій - публікацією в блозі? Ці бази даних використовують концепцію наборів (collections). Будь-який документ незалежно від його схеми, зіставлений з конкретним набором (наприклад, набором student), можна витягти при запиті даних з цього набору. Також для вказівки типу нерідко використовується будь-яке поле. Це набагато спрощує операції пошуку, але вирішувати, що саме має бути включено в набір, а що - ні, вам доведеться самостійно.

База даних без схеми

Запис student, описана вище, містить свою схему. Кожен запис відповідає за власну схему, навіть якщо вона міститься в єдиній базі даних або наборі. І одна із записів student не обов'язково повинна відповідати іншому записі student. Звичайно, ваше ПО має розуміти відмінності між ними. Цю гнучкість можна було б задіяти для підвищення ефективності. Наприклад, навіщо зберігати null-значення? Коли властивість начебто most_repeated_class не має значення, ви могли б зробити наступне:

підтримка транзакцій

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

Бази даних документів і DDD

Одна з базових концепцій розробки, керованої предметною областю (domain-driven development, DDD), відноситься до моделювання предметної області із застосуванням агрегатних коренів. При плануванні класів предметної області (які можуть стати документами у вашій базі даних) ви можете шукати дані, які найчастіше є самодостатніми (скажімо, замовлення з його позиціями), і концентруватися на них як на індивідуальній структурі даних. В системі замовлень у вас, ймовірно, також будуть клієнти і продукти. Але до замовлення можна звертатися без необхідності отримання інформації про клієнта, а продукт можна було б використовувати без обов'язкового доступу до замовлень, в яких він присутній. Тобто, хоча ви виявите багато можливих самодостатніх структур даних (той же замовлення з його позиціями), це не виключає в певних сценаріях необхідності або можливості приєднання даних через зовнішні ключі.

До всіх баз даних додаються керівництва по різним доступним шаблонами, а також вказується, які з них дозволили частіше досягати успіху їх користувачам. Наприклад, в документації MongoDB йдеться про шаблон Array of Ancestors, який прискорює доступ до пов'язаних даними при приєднанні документів.

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

Запити та оновлення

У кожній базі даних є API для запитів і оновлень. Хоча вони можуть не бути частиною базового API, через надбудови надаються різноманітні мовні API. Для введення .NET Framework в світ баз даних документів RavenDB підтримує запити через LINQ - прекрасна можливість для .NET-розробників.

Інші запити покладаються на зумовлені уявлення - відповідний шаблон називається map / reduce (зіставлення / скорочення). Частина процесу, що відноситься до зіставлення, використовує уявлення, і коло її завдань різниться в різних базах даних. Зіставлення також дозволяє базі даних розподіляти обробку запиту між декількома процесорами. Скорочення приймає результат, отриманий на етапі зіставлення запиту (або запитів, якщо він був розподілений), і агрегує дані в результати, які повертаються клієнту.

Map / reduce - це шаблон, і в різних базах даних він реалізований по-різному. Роб Ештон (Rob Ashton) надав цікаве порівняння того, як RavenDB і CouchDB виконують зіставлення / скорочення (bit.ly/94OCME).

Якщо RavenDB вимагає наявності визначених уявлень для запитів, а CouchDB дозволяє запитувати тільки через зіставлення / скорочення, то MongoDB (також використовує уявлення і зіставлення / скорочення) додатково підтримує спеціалізовані запити (ad hoc querying). Однак можливість виконувати спеціалізовані запити здебільшого втрачається, коли ви відходите від відомих схем і реляційної природи баз даних SQL.

Революція в базах даних

Під парасолькою NoSQL ховається дуже багато не реляційних баз даних. І тепер, коли двері відкрилися, їх стане ще більше в міру того, як програмісту вивчатимуть, що є, а потім мріяти про те, що можна було б вдосконалити в них. Я вважаю, що RavenDB - відмінний приклад цього, і ви можете спостерігати за тим, як рейху розвиває свою базу даних відповідно до своїми задумами і побажаннями користувачів.

Мені здається, що інтрига навколо цих баз даних заразлива. Тепер я копаю все глибше і вивчаю нові бази даних. Але навіть ті три з них, про які я розповіла вам, настільки цікаві, що вибрати тільки одну з них досить важко. Зараз мною рухає чисте цікавість, а не реальна бізнес-завдання, і в поточних проектах мене цілком задовольняють реляційні бази даних.

Висловлюю подяку за рецензування статті експертам Тедові Ньюарду (Ted Neward) і Савас Парастатідісу (Savas Parastatidis).