Сегодня перед нами стоит задача глубже понять массивы и также более глубоко сравнить их с JSONB, рассмотреть их сильные и слабые стороны и выбрать лучшие практики для их использования в реальных задачах.
Массивы vs JSONB: мини-черепашки данных vs гибкость в коробочке
Вы уже хорошо знаете, что в массивах PostgreSQL можно хранить значения любого одного типа данных: массив чисел, строк или дат. Пример: список оценок студента, где все элементы — числа.
-- Таблица со студентами и их оценками
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT,
grades INTEGER[] -- массив оценок
);
JSONB, в отличие от массива, представляет собой хранение данных в виде JSON-структуры. Это сильно напоминает всем знакомый JavaScript-объект, но с преимуществом быстрого парсинга и индексирования. В JSONB можно хранить как упорядоченные списки, так и объекты с ключами и значениями.
-- Таблица со студентами и различными данными о них
CREATE TABLE students_details (
id SERIAL PRIMARY KEY,
name TEXT,
details JSONB -- гибкая JSON-структура
);
Пример данных в JSONB:
{
"grades": [90, 82, 77],
"address": {
"city": "Berlin",
"zip": "352912"
}
}
Итак, массивы — это упрощённый способ работы со списками значений, а JSONB предоставляет значительно больше возможностей для сложных данных.
Основные различия между массивами и JSONB
| Признак | Массивы | JSONB |
|---|---|---|
| Тип структуры | Линейная структура данных | Иерархическая структура данных |
| Типы элементов | Только один тип данных | Разные типы данных |
| Размер структуры | Фиксированный (линейный) | Гибкий, может включать списки и объекты |
| Скорость доступа | Высокая при фиксированных данных | Медленнее при сложных поисках |
| Индексация | Хорошо поддерживает индексацию | Требует индексации типа GIN |
| Применение | Простой список или массив значений | Сложные данные: вложенные объекты/листы |
Теперь рассмотрим, как это всё работает на практике.
Когда использовать массивы?
Допустим, у нас есть база данных с книгами, где каждая книга может относиться к нескольким жанрам. Массив здесь будет хорошим выбором.
CREATE TABLE books (
id SERIAL PRIMARY KEY,
title TEXT,
genres TEXT[] -- массив жанров
);
-- Пример вставки книги с несколькими жанрами
INSERT INTO books (title, genres)
VALUES ('1984', ARRAY['Dystopia', 'Political Fiction', 'Science Fiction']);
Массивы хороши, если вы уверены, что:
- ваши данные можно строго хранить как список,
- списки будут небольшими и однотипными (например, строки или числа),
- вам нужно просто хранить и извлекать списки (без сложных операций).
Преимущества массивов
- Простота хранения однотипных данных.
- Удобны для небольших списков, таких как теги, категории или оценки.
Когда использовать JSONB?
Теперь представим, что мы хотим хранить более сложные данные о книгах, включая жанры, ISBN и рейтинг. Здесь массивы уже не подходят — настало время JSONB.
CREATE TABLE books_details (
id SERIAL PRIMARY KEY,
title TEXT,
details JSONB -- детали книги в виде JSONB
);
-- Пример вставки сложной информации о книге
INSERT INTO books_details (title, details)
VALUES (
'1984',
'{"genres": ["Dystopia", "Political Fiction", "Science Fiction"],
"isbn": "9780451524935",
"rating": 8.9}'
);
JSONB хорош, если вам нужно:
- хранить сложные или разнородные данные (числа, строки, списки, объекты),
- динамически добавлять параметры без изменения структуры таблицы,
- хранить вложенные данные (например, адреса, характеристики, настройки).
Преимущества JSONB
- Высокая гибкость. Вы можете добавлять новые ключи и значения без изменения структуры таблицы.
- Подходит для хранения сложных данных, например, JSON-ответов API.
Выбор между массивами и JSONB
Если нужно хранить только списки однотипных данных — используйте массивы. Например:
-- Хранение ID участников мероприятий
CREATE TABLE events (
id SERIAL PRIMARY KEY,
participant_ids INTEGER[]
);
Если данные разнородные или сложные — лучше использовать JSONB. Например:
-- Хранение информации о клиентах с адресами
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
info JSONB
);
Под индексирование массивы и JSONB имеют разные подходы. Для массивов чаще используют GIN индексы, а для JSONB — GIN и BTREE, в зависимости от структуры данных.
Производительность
Массивы обрабатываются быстрее при типовых задачах поиска. JSONB немного медленнее, но выигрывает в гибкости. Если вы хотите просто искать элементы (например, жанры или ID), массивы будут быстрее:
-- Использование массивов с индексом GIN
CREATE INDEX idx_genres ON books USING GIN(genres);
-- Фильтрация книг по жанру
SELECT * FROM books WHERE genres @> ARRAY['Science Fiction'];
Проверка наличия данных
В JSONB больше возможностей с фильтрацией по ключам:
-- Проверка наличия ключа "genres"
SELECT * FROM books_details WHERE details ? 'genres';
-- Проверка наличия элемента в списке
SELECT * FROM books_details WHERE details->'genres' ?| ARRAY['Fantasy', 'Dystopia'];
Массивы позволяют искать значения напрямую:
-- Проверка наличия элемента в массиве
SELECT * FROM books WHERE genres @> ARRAY['Fantasy'];
Гибкость структур
JSONB будет незаменим, если данные имеют сложные вложенные структуры:
{
"genres": ["Fantasy", "Adventure"],
"ratings": {"goodreads": 8.5, "amazon": 4.7}
}
Для массивов это будет недостижимо без нормализации или дополнительных полей.
В итоге, массивы и JSONB — это не конкуренты, а инструменты для разных задач. Если данные похожи на список — используйте массивы. Если же у вас сложные, вложенные или разнородные данные — смело берите JSONB. Главное — помнить про производительность и индексацию!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ