PostgreSQL - 来自许多表和OR条件的字段的gin索引
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PostgreSQL - 来自许多表和OR条件的字段的gin索引相关的知识,希望对你有一定的参考价值。
这是我非常简化的业务需求(使用PostgreSQL 10.1):
有两个表order
和customer
,它们使用join从db一起检索。两个表都包含必须使用ILIKE
关键字进行过滤的字段。然后我有两个gin
索引来提高查询性能:
CREATE INDEX order_type ON orderd USING gin (type gin_trgm_ops);
CREATE INDEX customer_name ON customer USING gin (name gin_trgm_ops);
现在我希望我的查询看起来像这样:
SELECT * FROM orderd o JOIN customer c ON c.id=o.customer_id
WHERE o.type ILIKE '%user_query%' OR c.name ILIKE '%user_query%';
我希望它使用索引,但EXPLAIN ANALYZE
显示不同的东西。这是我经过多次试验后的观察结果:
- 如果我尝试单一条件,没有
OR
,它的工作原理(使用索引) - 如果我用
OR
替换AND
- 它有效 - 如果我在同一个表上有两个索引它可以工作(对于
OR
和AND
)
但是,如果我想使用来自不同表和OR
条件的索引,它看起来无法工作。这是为什么?有没有办法使它工作?
我的实际业务场景要复杂得多,有两个以上的表和两个以上的字段,还有其他过滤器,还有一些在查询中计算的统计数据,所以我必须在单个查询中实现所有过滤。我有什么想法可以做到这一点?
答案
你可以尝试使用UNION/UNION ALL
:
SELECT *
FROM orderd o
JOIN customer c
ON c.id=o.customer_id
WHERE o.type ILIKE '%user_query%'
UNION ALL
SELECT *
FROM orderd o
JOIN customer c
ON c.id=o.customer_id
WHERE c.name ILIKE '%user_query%';
我假设OR EXPANSION
的工作方式与Oracle类似。
为避免重复(在某种程度上),您可以使用CTE
:
WITH cte AS (
SELECT *
FROM orderd o
JOIN customer c
ON c.id=o.customer_id
)
SELECT *
FROM cte
WHERE type ILIKE '%user_query%' --predicate pushdown should do the job
UNION ALL
SELECT *
FROM cte
WHERE name name ILIKE '%user_query%';
以上是关于PostgreSQL - 来自许多表和OR条件的字段的gin索引的主要内容,如果未能解决你的问题,请参考以下文章