Я успешно их использую для агрегирования рекурсивных ссылок на деревья с использованием триггеров.
Например, предположим, что у вас есть дерево категорий, и вы хотите найти товары в любой из категорий (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;
Другой способ - предварительно агрегировать необходимые данные:
* * 1010
Одна из проблем, связанных с описанным выше подходом, заключается в том, что оценки строк для оператора && являются ненужными. (Селективность - это функция-заглушка, которая еще не написана, и в результате получается что-то вроде 1/200 строк независимо от значений в ваших агрегатах.) Другими словами, вы можете очень хорошо закончить сканирование индекса, где последующее сканирование было бы правильно.
Чтобы обойти это, я увеличил статистику по столбцу с индексом 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;
(То же самое касается оператора <@ ...) </p>