Что такое утилита типа массива?

Я полностью новичок с 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 также имеет геометрические типы, простые типы ключей/значений, и поддерживает построение различных других составных типов.

Обычно лучше использовать традиционные таблицы ассоциаций, но нет ничего плохого в том, что в вашем инструменте больше инструментов.

Ответ 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;

(То же самое относится к оператору < @...)