这是我非常简化的业务需求(使用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
条件的索引,它看起来无法工作。这是为什么?有没有办法让它发挥作用?
我的实际业务场景要复杂得多,有两个以上的表和两个以上的字段,还有其他过滤器,还有一些在查询中计算的统计数据,所以我必须在单个查询中实现所有过滤。我有什么想法可以做到吗?
答案 0 :(得分:1)
您可以尝试使用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%';