Классический SQL не предусматривает хранение нескольких значений в одной ячейке — реляционная модель требует нормализации. Однако, в современных задачах часто встречаются поля типа "список тегов", "шкала оценок", где удобно оперировать именно множеством значений на уровне отдельной строки. Некоторые СУБД (PostgreSQL, Oracle) предоставляют типы данных ARRAY или аналогичные механизмы.
Использование массивов нарушает принцип нормализации, затрудняет многие операции (фильтрация, обновление, индексация), а также делает код менее переносимым между СУБД. Но бывает удобно или неизбежно — например, для кэширования или быстрого поиска по небольшим спискам значений.
CREATE TABLE products ( id SERIAL PRIMARY KEY, tags TEXT[] ); -- Вставка: INSERT INTO products(tags) VALUES (ARRAY['eco','sale','hot']); -- Поиск по массиву: SELECT * FROM products WHERE 'eco' = ANY (tags);
Ключевые особенности:
Можно ли индексировать отдельные элементы массива?
В PostgreSQL — да, через GIN/GIST-индексы:
CREATE INDEX idx_tags ON products USING GIN (tags);
Как быстрее проверить вхождение значения в массив в строковой колонке через разделитель?
SQL стандартно не умеет, используют поиск по шаблону:
SELECT * FROM users WHERE ',admin,' like concat('%,',role,',%');
Но этот подход ненадёжен и медленный.
Сколько значений можно хранить в массиве, и что ограничивает?
Ограничение зависит от СУБД — например, в PostgreSQL ограничение только на размер строки (1–2 МБ).
В ecommerce проекте теги товаров решили хранить как строку через запятую в одном столбце. Очень затруднился быстрый поиск товаров по тегу, ошибки в фильтрации, повторение тегов случалось из-за ошибок парсинга.
Плюсы:
Минусы:
В PostgreSQL для маленьких, неизменяемых наборов (user roles) использовали ARRAY и GIN-индекс. Для больших — отдельную таблицу ролей.
Плюсы:
Минусы: