【问题标题】:PostgreSQL - gin indexes on fields from many tables and OR conditionsPostgreSQL - 来自许多表和 OR 条件的字段的 gin 索引
【发布时间】:2018-03-05 19:24:10
【问题描述】:

这是我非常简化的业务需求(使用 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 条件的索引,它似乎无法工作。这是为什么?有什么办法让它工作吗?

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

【问题讨论】:

    标签: sql postgresql indexing


    【解决方案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%';
    

    【讨论】:

    • 是的,我们正在考虑这个问题,但是就像我写的那样,查询非常复杂,我担心为每个字段复制它会对性能和代码可读性产生不良影响。但如果我没有找到任何解决方案,我可能会这样做。
    • @xersiee 您可以使用 CTE/LATERAL JOINS 在某种程度上避免重复。
    • 我会看看我能做什么,谢谢你的帮助。无论如何,它不工作很有趣(也很烦人!):)
    猜你喜欢
    • 2012-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    • 2013-11-26
    • 1970-01-01
    相关资源
    最近更新 更多