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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PostgreSQL - 来自许多表和OR条件的字段的gin索引相关的知识,希望对你有一定的参考价值。

这是我非常简化的业务需求(使用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

但是,如果我想使用来自不同表和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索引的主要内容,如果未能解决你的问题,请参考以下文章

4.2. PostgreSQL值表达式

从 Postgresql 表中绘制表和关系

PostgreSQL对现有,新建的表和视图授权给用户

PostgreSQL对现有,新建的表和视图授权给用户

PostgreSQL对现有的未来的表和视图授权给用户

sql PostgreSQL:如何处理表和视图依赖项