在 JOIN 中没有同时在两列上使用杜松子酒

Posted

技术标签:

【中文标题】在 JOIN 中没有同时在两列上使用杜松子酒【英文标题】:gin not used on two columns at the same time in a JOIN 【发布时间】:2016-07-15 06:27:10 【问题描述】:

我有两张桌子,productsproducts_names

我在两个表中使用 GIN 索引在两列中进行 ILIKE 匹配,但仅当我仅在一列上执行 ILIKE 时才使用 GIN。

我通过执行 UNION 做了一个解决方法,但我想知道为什么它没有像我想象的那样工作。

n.namee.producer 这两列都是 VARCHAR 具有 GIN 索引:

CREATE INDEX products_producer_gin_idx ON products USING gin (producer gin_trgm_ops);
CREATE INDEX products_names_name_gin_idx ON products_names USING gin (name gin_trgm_ops);

SELECT with JOIN and ILIKE 不使用 GIN

testdb=# explain (analyze, verbose) 
            SELECT n.name, e.producer
            FROM products e
            INNER JOIN products_names n ON 
                n.product_id = e.product_id

            WHERE

                    n.name ilike '%eda%' or e.producer ilike '%eda%' 


limit 20;
                                                                                 QUERY PLAN                                                                                 
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.42..2725.92 rows=20 width=60) (actual time=0.582..62.658 rows=20 loops=1)
   Output: n.name, e.producer
   ->  Nested Loop  (cost=0.42..669928.73 rows=4916 width=60) (actual time=0.582..62.652 rows=20 loops=1)
         Output: n.name, e.producer
         ->  Seq Scan on public.products e  (cost=0.00..220800.16 rows=446716 width=29) (actual time=0.002..5.363 rows=17067 loops=1)
               Output: e.producer, e.product_id
         ->  Index Scan using products_names_pkey on public.products_names n  (cost=0.42..1.00 rows=1 width=39) (actual time=0.003..0.003 rows=0 loops=17067)
               Output: n.product_id, n.lang, n.name, n.name2, n.name3, n.products
               Index Cond: (n.product_id = e.product_id)
               Filter: (((n.name)::text ~~* '%eda%'::text) OR ((e.producer)::text ~~* '%eda%'::text))
               Rows Removed by Filter: 1
 Planning time: 0.559 ms
 Execution time: 62.677 ms
(13 Zeilen)

Zeit: 63,529 ms

在单个列 n.name 上选择 使用 GIN

testdb=# explain (analyze, verbose)
            SELECT n.name, e.producer
            FROM products e
            INNER JOIN products_names n ON 
                n.product_id = e.product_id

            WHERE

                    n.name ilike '%eda%'                   

limit 20;
                                                                         QUERY PLAN                                                                          
-------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=58.34..260.70 rows=20 width=60) (actual time=0.257..0.458 rows=20 loops=1)
   Output: n.name, e.producer
   ->  Nested Loop  (cost=58.34..49564.37 rows=4893 width=60) (actual time=0.256..0.454 rows=20 loops=1)
         Output: n.name, e.producer
         ->  Bitmap Heap Scan on public.products_names n  (cost=57.92..14890.29 rows=4893 width=39) (actual time=0.245..0.333 rows=20 loops=1)
               Output: n.product_id, n.lang, n.name, n.name2, n.name3, n.products
               Recheck Cond: ((n.name)::text ~~* '%eda%'::text)
               Heap Blocks: exact=18
               ->  Bitmap Index Scan on products_names_name_gin_idx  (cost=0.00..56.70 rows=4893 width=0) (actual time=0.160..0.160 rows=797 loops=1)
                     Index Cond: ((n.name)::text ~~* '%eda%'::text)
         ->  Index Scan using products_pkey on public.products e  (cost=0.42..7.08 rows=1 width=29) (actual time=0.005..0.006 rows=1 loops=20)
               Output: e.producer, e.product_id
               Index Cond: (e.product_id = n.product_id)
 Planning time: 1.000 ms
 Execution time: 0.494 ms
(15 Zeilen)

Zeit: 2,563 ms

【问题讨论】:

PostgreSQL LIKE query performance variations的可能重复 【参考方案1】:

这些只是一种解决方法。您可以通过此推送 postgres 来处理索引。

SELECT * from
    (SELECT n.name, e.producer
        FROM products e
        INNER JOIN products_names n ON 
            n.product_id = e.product_id) a    
    WHERE
            name ilike '%eda%' or producer ilike '%eda%' 

编辑-或者试试这个

SELECT * FROM
    (SELECT n.name, e.producer
        FROM products e
        INNER JOIN products_names n ON 
            n.product_id = e.product_id
        WHERE
                n.name ilike '%eda%'  )a
    WHERE a.producer ilike '%eda%' 

【讨论】:

这对我来说根本不起作用。它没有使用 GIN,甚至慢得多(3 秒),可能是因为内部 SELECT 基本上是连接包含所有内容的表,然后 ILIKE 正在过滤。 你能试试第二个吗? 第二个有效,这是一个好主意,但它提供了错误的结果,因为内部选择是按名称过滤的,而生产者完全被忽略了。如果没有带有“eda”的生产者,则不返回任何不正确的内容 对不起,是“或”,我以为是“和” 因此,与 union 一起工作是一件好事。试着在这里问。你会得到更好的解决方案irc.lc/freenode/postgresql/irctc@@@

以上是关于在 JOIN 中没有同时在两列上使用杜松子酒的主要内容,如果未能解决你的问题,请参考以下文章

为啥 goroutine 从杜松子酒的处理程序一直有效[关闭]

golang Golang +杜松子酒でファイルをダウンロードさせる

在 Amazon Redshift 中是不是可以在两列上设置条件?

在两列上使用 COUNT 和 GROUP BY 的 SQL 查询非常慢

模式构建器 laravel 迁移在两列上是唯一的

如何使用 UCanAccess 在两列上创建具有唯一约束的表?