PostgreSQL - 来自许多表和OR条件的字段的gin索引

时间:2018-03-05 19:24:11

标签: sql postgresql indexing

这是我非常简化的业务需求(使用PostgreSQL 10.1):

有两个表ordercustomer使用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显示不同的东西。经过多次试验后,这些是我的观察结果:

  1. 如果我尝试使用单一条件,但没有OR,则可以使用(使用索引)
  2. 如果我将OR替换为AND - 它可以正常工作
  3. 如果我在同一张桌子上有两个索引,则可以使用ORAND
  4. 但是如果我想使用来自不同表和OR条件的索引,它看起来无法工作。这是为什么?有没有办法让它发挥作用?

    我的实际业务场景要复杂得多,有两个以上的表和两个以上的字段,还有其他过滤器,还有一些在查询中计算的统计数据,所以我必须在单个查询中实现所有过滤。我有什么想法可以做到吗?

1 个答案:

答案 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%';