Что такое утилита типа массива?
Я полностью новичок с postgresql, но у меня есть хороший опыт работы с mysql. Я читал документацию, и я обнаружил, что postgresql имеет тип массива. Я довольно смущен, так как не могу понять, в каком контексте этот тип может быть полезен в rdbms. Почему мне нужно выбирать этот тип вместо того, чтобы использовать классическое отношение ко многим?
Спасибо заранее.
Ответы
Ответ 1
Я использовал их, чтобы упростить работу с деревьями (например, потоками комментариев). Вы можете сохранить путь от корня дерева до единственного node в массиве, каждый номер в массиве - это номер ветки для этого node. Затем вы можете делать такие вещи:
SELECT id, content
FROM nodes
WHERE tree = X
ORDER BY path -- The array is here.
PostgreSQL будет сравнивать элемент массива по элементу естественным образом, поэтому ORDER BY path
сбрасывает дерево в разумном линейном порядке отображения; то вы проверите длину path
, чтобы определить глубину node, и это даст вам отступ, чтобы получить право на рендеринг.
Вышеприведенный подход позволяет получить данные из базы данных на отображаемую страницу с одним проходом данных.
PostgreSQL также имеет геометрические типы, простые типы ключей/значений, и поддерживает построение различных других составных типов.
Обычно лучше использовать традиционные таблицы ассоциаций, но нет ничего плохого в том, что в вашем инструменте больше инструментов.
Ответ 2
Один пользователь SO использует его для того, что кажется машинным переводом. Комментарии к следующему вопросу могут быть полезны при понимании его подхода.
Ответ 3
Я успешно их использовал для агрегирования рекурсивных ссылок на дерево с помощью триггеров.
Например, предположим, что у вас есть дерево категорий, и вы хотите найти продукты в любой из категорий (1,2,3) или любой из их подкатегорий.
Один из способов сделать это - использовать уродливый оператор with recursive
. Это позволит вывести план, заполненный слиянием/хешем, на всех таблицах и случайным материализоваться.
with recursive categories as (
select id
from categories
where id in (1,2,3)
union all
...
)
select products.*
from products
join product2category on...
join categories on ...
group by products.id, ...
order by ... limit 10;
Другим является предварительная сводка необходимых данных:
categories (
id int,
parents int[] -- (array_agg(parent_id) from parents) || id
)
products (
id int,
categories int[] -- array_agg(category_id) from product2category
)
index on categories using gin (parents)
index on products using gin (categories)
select products.*
from products
where categories && array(
select id from categories where parents && array[1,2,3]
)
order by ... limit 10;
Одной из проблем с вышеупомянутым подходом является оценка строк для && Оператор - хлам. (Селективность - это заглушка, которая еще должна быть записана, и приводит к чему-то вроде строк 1/200 независимо от значений в ваших агрегатах.) Другими словами, вы вполне можете получить сканирование индекса, где сканирование seq будет правильным.
Чтобы обойти это, я увеличил статистику столбца с индексом gin и периодически просматривал pg_stats, чтобы извлечь более подходящую статистику. Когда беглый взгляд на эти статистические данные показывает, что использование && поскольку указанные значения вернут неправильный план, я переписываю применимые вхождения && с arrayoverlap() (последний имеет выборочную селективность 1/3), например:
select products.*
from products
where arrayoverlap(cat_id, array(
select id from categories where arrayoverlap(parents, array[1,2,3])
))
order by ... limit 10;
(То же самое относится к оператору < @...)