Что такое тип Array в PostgreSQL?
Тип Array в PostgreSQL
PostgreSQL поддерживает массивы как встроенный тип данных. Столбец таблицы может хранить массив значений любого базового типа: целых чисел, строк, булевых значений, JSON и т.д. Это позволяет избежать создания отдельных таблиц для списков однотипных значений в некоторых сценариях.
Объявление столбца с типом Array
Массив объявляется путём добавления квадратных скобок к базовому типу:
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
product_ids INTEGER[], -- одномерный массив целых чисел
tags TEXT[], -- массив строк
matrix INTEGER[][] -- двумерный массив
);
Альтернативный синтаксис через ARRAY:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
attributes TEXT ARRAY -- эквивалентно TEXT[]
);
Вставка данных
-- Литерал массива через фигурные скобки
INSERT INTO orders (product_ids, tags)
VALUES ('{1, 2, 3}', '{sale, new, featured}');
-- Конструктор ARRAY[]
INSERT INTO orders (product_ids, tags)
VALUES (ARRAY[1, 2, 3], ARRAY['sale', 'new', 'featured']);
Доступ к элементам
Индексация в PostgreSQL начинается с 1, а не с 0:
-- Получить первый элемент массива тегов
SELECT tags[1] FROM orders WHERE id = 1;
-- Срез массива (элементы с 1 по 3)
SELECT tags[1:3] FROM orders WHERE id = 1;
Операторы для работы с массивами
-- Проверка вхождения элемента (оператор @>)
SELECT * FROM orders WHERE tags @> ARRAY['sale'];
-- Пересечение массивов (&&)
SELECT * FROM orders WHERE tags && ARRAY['sale', 'new'];
-- Конкатенация массивов (||)
SELECT ARRAY[1,2] || ARRAY[3,4]; -- {1,2,3,4}
-- Поиск через ANY
SELECT * FROM orders WHERE 'sale' = ANY(tags);
-- Поиск через ALL
SELECT * FROM orders WHERE 5 > ALL(ARRAY[1, 2, 3]);
Функции для работы с массивами
-- Длина массива по заданному измерению
SELECT array_length(tags, 1) FROM orders;
-- Добавить элемент в конец
SELECT array_append(ARRAY[1,2,3], 4); -- {1,2,3,4}
-- Убрать элемент
SELECT array_remove(ARRAY[1,2,3,2], 2); -- {1,3}
-- Развернуть массив в строки
SELECT unnest(ARRAY[1,2,3]); -- возвращает 3 строки
-- Агрегация значений в массив
SELECT array_agg(id) FROM orders;
Индексирование массивов
Для эффективного поиска по массивам используется GIN-индекс:
CREATE INDEX idx_orders_tags ON orders USING GIN (tags);
-- После создания GIN-индекса запросы с @> и && работают быстро
SELECT * FROM orders WHERE tags @> ARRAY['sale'];
Когда использовать Array
Massив уместен, когда:
- порядок элементов важен
- набор значений жёстко привязан к родительской записи
- не нужны отдельные запросы к элементам как к сущностям
Вместо массива стоит предпочесть отдельную таблицу, если нужны внешние ключи, сложные запросы к элементам или частые обновления отдельных значений.
Что хочет услышать интервьюер
Понимание синтаксиса объявления массива и двух вариантов записи (TEXT[] и TEXT ARRAY)
Знание того, что индексация в PostgreSQL начинается с 1
Умение использовать операторы @>, &&, ANY, ALL для поиска по массивам
Знание ключевых функций: unnest, array_agg, array_length, array_append
Понимание необходимости GIN-индекса для эффективных запросов по массивам
Пример: Основные операции с массивами в PostgreSQL
-- Создание таблицы с массивом
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
tags TEXT[]
);
-- Вставка данных
INSERT INTO articles (title, tags)
VALUES
('Введение в PostgreSQL', ARRAY['postgresql', 'database', 'beginner']),
('Оптимизация запросов', ARRAY['postgresql', 'performance', 'advanced']);
-- Поиск статей с тегом 'postgresql'
SELECT title FROM articles WHERE 'postgresql' = ANY(tags);
-- Поиск статей, имеющих ОБА тега
SELECT title FROM articles WHERE tags @> ARRAY['postgresql', 'advanced'];
-- Добавить тег к существующей записи
UPDATE articles
SET tags = array_append(tags, 'hot')
WHERE id = 1;
-- Развернуть теги в строки для агрегации
SELECT tag, COUNT(*) AS usage_count
FROM articles, unnest(tags) AS tag
GROUP BY tag
ORDER BY usage_count DESC;
-- GIN-индекс для быстрого поиска
CREATE INDEX idx_articles_tags ON articles USING GIN (tags);
Типичные ошибки
Начинают индексацию с 0 вместо 1, что возвращает NULL
Используют LIKE или = для поиска элемента в массиве вместо оператора ANY или @>
Не создают GIN-индекс при необходимости фильтрации по содержимому массива, из-за чего происходит Seq Scan
Злоупотребляют массивами там, где нужна отдельная связанная таблица (нарушение 1NF)
Путают синтаксис литерала '{1,2,3}' и конструктора ARRAY[1,2,3]


