Коли використовувати неструктуровані типи даних в PostgresSQL? Порівняння Hstore vs. JSON vs. JSONB

З тих пір як Postgres почав підтримувати NoSQL (за допомогою HStore, JSON і JSONB), питання про те, коли використовувати Postgres в реляційному режимі, а в яких в режимі NoSQL, став підніматися досить часто. Чи вийде у вас повністю відмовитися від традиційних структур таблиць і працювати з уявленнями документів в майбутньому? Змішувати чи обидва підходу? Відповідь на це питання не дивний — все залежить від багатьох факторів. Кожна нова модель зберігання даних, включаючи Hstore, JSON і JSONB має свої ідеальні варіанти застосування. Тут ми копнемо глибше і дізнаємося про особливості кожної з них і подивимося що коли використовувати

HStore
Якщо виключити XML, Hstore був першим по-справжньому неструктурованим типом даних, який додається до Postgres. Hstore був доданий досить давно в Postgres 8.3 до upsert, потокової реплікації до віконних функцій. Hstore це по суті сховище ключ/значення безпосередньо в Postgres. Використовуючи Hstore ви обмежені у виборі використовуваного типу даних. По суті у вас є тільки рядки. У вас навіть немає вкладеності даних; Коротше кажучи, це однорівневий тип даних ключ/значення.
Гідністю Hstore є те, що вам не потрібно визначати ключі (на відміну від стовпців) заздалегідь. Ви можете просто вставити запис, і вона буде зберігати всі необхідні дані. Скажімо, у вас є приклад скрипта на створення таблиці:
CREATE TABLE products (
id serial PRIMARY KEY,
name varchar,
attributes hstore
);

З допомогою Hstore ви можете вставити все, що ви хочете в колонку атрибутів. У цьому випадку запит на додавання цих ключів і значень буде виглядати наступним чином:
INSERT INTO products (name, attributes) VALUES (
'Geek Love: A Novel',
'author => "Katherine Dunn",
pages => 368,
category => fiction'
);

Запит на вибірку буде мати вигляд:
SELECT name, attributes->'author' author as
FROM products
WHERE attributes->'category' = 'fiction'

Очевидною перевагою такого підходу є гнучкість, але ось де він дійсно проявляє себе повністю, так це можливістю використовувати різні типи індексів. Зокрема, GIN або GiST індекс буде індексувати кожен ключ і значення в межах Hstore. Тобто, при фільтрації буде використаний доданий індекс, у разі якщо цього вимагатиме планувальник Postgres.
Оскільки Hstore не є повним еквівалентом документа, важливо зрозуміти вигідно використовувати його в якості такого.
Якщо у вас є реляційні дані і також деякі дані, які не завжди можуть існувати в колонці, то такий підхід може статьотличным рішенням. Наприклад, в більшості випадків атрибути каталогів продукції можуть бути чудовим прикладом для такоготипа даних. Тоді, для деяких продуктів, таких як книги (які ви зберігаєте у окремій таблиці «Products») можуть бути визначені такі параметри, як жанр, рік видання. В іншому випадку для продуктів, таких як одяг, яку ви теж зберігайте в цій же таблиці, можуть бути визначені інші параметри — розмір і колір. Додавати ж стовпця в таблицю продуктів для кожного можливого параметра надмірно і невиправдано.
JSON
Починаючи з версії 9.2 в Postgres реалізована підтримка JSON. Тепер, Postgres може скласти конкуренцію MongoDB. (Хоча функціональність JSON в Postgres 9.2, звичайно, трохи перебільшена. Про це нижче.)
Тип даних в форматі JSON в Postgres, якщо розібратися в значній мірі просто текстове поле. Все що ви отримаєте з типом даних JSON так це валідацію значення при вставці. Postgres забезпечує дотримання формату JSON. Одним невеликим потенційною перевагою над JSONB (який ми розглянемо наступним) є те, що JSON зберігає відступи в даних, що надходять в БД. Так що якщо ви дуже вимогливі до форматування даних або вам необхідно зберегти запис у тій чи іншій структурі, JSON може виявитися корисним.
Крім того, з плином часу Postgres придбав ряд досить корисних функцій. Повинні ви використовувати JSON? Адже, Postgres-ний тип JSON просто надає перевірку на полі. Якщо ви зберігаєте деяку форму даних журналу, яку рідко запитуєте, тип даних JSON в цьому випадку працює добре. Так як JSON досить простий, то він буде мати набагато більш високу пропускну здатність при вставці. Для чогось більш складного, я б рекомендував використовувати JSONB, який буде описаний нижче.
JSONB
Нарешті, в Postgres 9.4 ми отримали справжню і правильну підтримку JSON у вигляді JSONB. B означає «краще» (Better). JSONB — це бінарне представлення даних формату JSON. Це означає, що дані стискається і більш ефективні для зберігання, ніж звичайний текст. Крім того, під капотом у нього механізм, подібний Hstore. Технічно, коли-то при розробці, був майже реалізований тип Hstore2 і окремий тип JSON і згодом вони були об'єднані в JSONB в тому вигляді, як він є зараз.
Тип JSONB є в значній мірі те, що ви могли б очікувати від типу даних JSON. Він дозволяє реалізовувати вкладені структури, використовувати основні типи даних, а також має ряд вбудованих функцій для роботи з ним. Кращою частиною такої схожості з Hstore є індексація. Створення індексу GIN на колонці JSONB створить індекс по кожному ключу і значенням у межах цього документа JSON. Можливість індексації і вкладеність даних усередині документа означають, що JSONB перевершує Hstore в більшості випадків.
Хоча все ще залишається невеликий питання про те, в яких випадках слід використовувати виключно JSONB. Припустимо, ви створюєте базу даних документів і з усіх варіантів вибираєте Postgres. З пакетом, на зразок MassiveJS це може бути досить зручним.
Найбільш поширені приклади використання:
  1. Відстеження подій даних, додаючи змінюється payload події.
  2. Зберігання ігрових дані досить поширене, особливо там, де у вас є одиночна гра і змінюється схема даних на основі стану користувача.
  3. Інструменти, які об'єднують декілька джерел даних, приклад тут може бути інструментом, який інтегрує кілька баз даних клієнтів до Salesforce, до Zendesk або до чогось ще. Поєднання схем робить це більш болючою процедурою, чим вона повинна бути.
Давайте розглянемо інший приклад роботи з JSONB. Скрипт створює таблицю і вставляє деякі дані для прикладу:
CREATE TABLE integrations (id UUID, data JSONB);

INSERT INTO integrations VALUES (
uuid_generate_v4(),
'{
"service": "salesforce",
"id": "AC347D212341XR",
"email": "craig@citusdata.com",
"occurred_at": "8/14/16 11:00:00",
"added": {
"lead_score": 50
},
"updated": {
"updated_at": "8/14/16 11:00:00"
}
}');

INSERT INTO integrations (
uuid_generate_v4 (),
'{
"service": "zendesk",
"email": "craig@citusdata.com",
"occurred_at": "8/14/16 10:50:00",
"ticket_opened": {
"ticket_id": 1234,
"ticket_priority": "high"
}
}');

У наведеному вище випадку, можна легко знайти усі події, які сталися c користувачем з email craig@citusdata.com, а потім робити якісь дії. Наприклад, можна провести яку-небудь форму поведінкової аналітики, і обчислити користувачів, які зробили а потім foo bar, або зробити простий звіт.
Додавши індекс Gin всі дані в межах мого JSONB поля проіндексує автоматично:
CREATE INDEX idx_integrations_data ON integrations USING gin(data);

Висновок
У більшості випадків JSONB це, ймовірно, якраз те, що ви шукайте, коли плануєте використовувати нереляционый тип даних. Для Hstore і JSON можна також знайти хороше застосування хоч і в більш рідкісних випадках. JSONB не завжди вписується в модель даних. У випадку якщо ви можете нормалізувати схему, то у вас буде перевага, але якщо в схемі, велика кількість опціональних стовпців (наприклад, з даними про події) або одна схема сильно відрізняється від іншої, то JSONB підходить набагато краще.
Резумируя, алгоритм вибору рішення:
JSONB — В більшості випадків
JSON — Якщо ви обробляєте логи, вам не часто доводиться дані або запитувати не потрібно використовувати їх як щось більше ніж для завдань логування.
Hstorere — відмінно працює з текстовими даними на основі подання ключ-значення, але в цілому JSONB також відмінно справляється з цим завданням.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.