Наилучшим решением для нормализованной таблицы является «Таблица закрытия», как рекомендовано этим этим вопросом / решением .
В других стратегиях индексирования мы можем использовать подсказки этого вопроса / ответа , которые предлагают попробовать pg_trgm
модуль. См. Также https://www.postgresql.org/docs/current/pgtrgm.html
Давайте проверим все решения.
Грубая сила (индексация)
Преимущество "грубой силы" заключается в том, что отсутствие изменений в структуре данных, только добавление индекса, заключается в том, что в контексте больших данных у нас есть дополнительное дисковое пространство. Итак, только проверено индексирование, без разбиения на реальное дерево и указатели.
Тест ltree
Поиск
См. Тесты по существу вопроса. Время выполнения: ~ 1300 мс.
Хорошие операторы иерархического поиска. Единственная проблема заключается в необходимости нового столбца для индекса, когда строка должна быть сохранена для другого использования или не в формате ltree
-esestion. Я использовал преобразование
trim(
replace(
regexp_replace(text_path,'[^A-Z0-9_/]+','_','ig'), -- clean
'/', -- the path separator at text_path
'.' -- the ltree separator
),
'.' -- clean
)::ltree
Так что, когда вы преобразуете, другая проблема, это не на 100% обратимо для повторного использования при приведении ltree2text()
.
Тест pg_trgm
поиск с оператором LIKE
Это более быстрый способ: ~ 200 мс
CREATE EXTENSION pg_trgm;
CREATE INDEX textpath_gist_idx ON t2_text USING gin (txt_path gin_trgm_ops);
EXPLAIN ANALYSE
SELECT count(*) n
FROM t2_text
WHERE txt_path LIKE 'first/second/%/etc_etc_etc/%'
; -- Planning Time: 0.133 ms
-- Execution Time: 195.524 ms
-- ... BUT, returns zero on COUNT result!
При индексации USING gin (colName gin_trgm_ops)
используется меньше места на диске, ~ 2G.
Проблема здесь не в производительности, а в что он не работает (!) и не является проблемой "two %
", потому что отлично работает с подобным запросом, поэтому он не надежен :
- COUNT
WHERE txt_path LIKE 'first/second/%/etc_etc_etc/%'
равно нулю. - COUNT
WHERE txt_path LIKE '%etc_etc_etc%'
правильно.
Кажется, ошибка PostgreSQL v12 (то же самое для других версий?).
Тест pg_trgm
поиск по регулярному выражению
При времени выполнения ~ 1000 мс это немного быстрее (и меньше потребление дискового пространства), чем ltree
и самый надежный оператор LIKE.
EXPLAIN ANALYSE
SELECT count(*) n
FROM t2_text
WHERE txt_path ~ '^first/second/.+/etc_etc_etc/'
-- Timing: Generation 2.312 ms, ..., Total 27.853 ms
-- Execution Time: 1017.293 ms
Таблица закрытия
Необходимо добавить id bigserial
, если не существует, и новую таблицу с предком и потомком , указывающим на оригинал Таблица. занимает больше дискового пространства и ... Могу ли я выполнить все запросы с этой моделью?
Он также потребляет больше времени программистов (!), Автоматизированных нет способ (это таблица шаблонов, но PostgreSQL не предлагает «стандартного решения») для создания дополнительной таблицы. Для запросов нет простого оператора .
... поэтому я не добавляю тест, это вики: если вы что-то здесь редактируете, я могу добавить тест, чтобы показать различия.
CREATE TABLE t2_treeclosure (
ancestor bigint NOT NULL,
descendant bigint NOT NULL,
PRIMARY KEY (ancestor,descendant),
FOREIGN KEY (ancestor) REFERENCES t2_text(id),
FOREIGN KEY (descendant) REFERENCES t2_text(id)
);
... иногда возможно уменьшить потребление диска оригинальной t2_text
таблицей, уменьшая текст, после того, как он пропал. Нужна функция для восстановления пути, et c. но может быть быстрым, если '' закрытие таблицы '' быстрее, чем методы "грубой силы".