Postgres / Rails - 使用GIN索引和其他过滤器的最有效方法是什么?

时间:2014-11-02 04:40:58

标签: ruby-on-rails postgresql indexing

我有一个名为"语句"的Postgres数据库表。它由140万条记录组成 - 每条记录都包含一个" statement_text"我使用GIN索引实现全文搜索的字段。我的球场猜测是每个" statement_text"包含大约50个单词(平均可能250个字符)。

我使用Rails创建了一个简单的搜索引擎,它利用了GIN索引,这在大多数情况下都非常快。我的问题是我希望它更快,最简单的方法就是过滤掉#34;语句中的其他一些字段" table - 其中一个," casefile,"包含大约6,500个唯一值,另一个包含#34; speaker,"包含大约8,000个唯一值。 (我在两者上都创建了b-tree索引。)

这应该在实践中起作用,因为用户搜索" statement_text"字段通常只对来自" casefile"的非常小的子集的结果感兴趣。或"发言者"值。问题是,使用EXPLAIN,我注意到Postgres经常要么完全放弃GIN索引,要么将它(看似)与我在" casefile"上的正常b-tree索引无效地结合起来。和"发言者"领域。这可能会导致查询时间过长。

为了防止这种情况发生,我更改了查询,因此它始终只有一个"其中" condition - " statement_text"查询术语,从而确保使用GIN索引 - 然后我pluck该字段以及" casefile"和"发言人",所以我可以遍历生成的数组,并在查询完成后过滤掉我不需要的所有数据。但这似乎是查询数据库的一种非常低效的方式,因为我在完成查询后立即丢弃了大部分返回的结果。

我的(相当开放式的)问题是:

1)是否有其他人遇到问题,让GIN索引与b-tree索引很好地配合?尽管我已经尝试过阅读这篇内容,无论是在SO还是其他地方,我仍然不确定GIN和b-tree索引是否真的在后端组合起来。< / p>

2)是否有更有效的方法来实现与我目前相同的结果?

非常感谢你。作为编码的相对新手,我发现SO非常有用。

更新:添加一些EXPLAIN语句来演示。

EXPLAIN for: SELECT "statements".* FROM "statements"  WHERE (to_tsvector('simple', statement_text) @@ to_tsquery('simple', 'hello'))
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on statements  (cost=373.48..4349.24 rows=2243 width=247)
   Recheck Cond: (to_tsvector('simple'::regconfig, statement_text) @@ '''hello'''::tsquery)
   ->  Bitmap Index Scan on index_statement_text  (cost=0.00..373.36 rows=2243 width=0)
     Index Cond: (to_tsvector('simple'::regconfig, statement_text) @@ '''hello'''::tsquery)

现在有一个额外的条件:

EXPLAIN for: SELECT "statements".* FROM "statements"  WHERE (to_tsvector('simple', statement_text) @@ to_tsquery('simple', 'hello') and casefile_id in (12,563,876,4303,1120,422,654,13,988,335))
                                                                                  QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on statements  (cost=417.81..425.80 rows=4 width=247)
   Recheck Cond: ((casefile_id = ANY ('{12,563,876,4303,1120,422,654,13,988,335}'::integer[])) AND (to_tsvector('simple'::regconfig, statement_text) @@ '''hello'''::tsquery))
   ->  BitmapAnd  (cost=417.81..417.81 rows=4 width=0)
         ->  Bitmap Index Scan on index_statements_on_casefile_id  (cost=0.00..44.40 rows=2363 width=0)
           Index Cond: (casefile_id = ANY ('{12,563,876,4303,1120,422,654,13,988,335}'::integer[]))
         ->  Bitmap Index Scan on index_statement_text  (cost=0.00..373.36 rows=2243 width=0)
           Index Cond: (to_tsvector('simple'::regconfig, statement_text) @@ '''hello'''::tsquery)

加入另一个:

EXPLAIN for: SELECT "statements".* FROM "statements"  WHERE (to_tsvector('simple', statement_text) @@ to_tsquery('simple', 'hello') and casefile_id in (12,563,876,4303,1120,422,654,13,988,335) and speaker_name in ('Seth Waxman'))
                                                                   QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on statements  (cost=46.70..48.70 rows=1 width=247)
   Recheck Cond: (((speaker_name)::text = 'Seth Waxman'::text) AND (casefile_id = ANY ('{12,563,876,4303,1120,422,654,13,988,335}'::integer[])))
   Filter: (to_tsvector('simple'::regconfig, statement_text) @@ '''hello'''::tsquery)
   ->  BitmapAnd  (cost=46.70..46.70 rows=1 width=0)
         ->  Bitmap Index Scan on index_statements_on_speaker_name_and_person_role_id  (cost=0.00..2.25 rows=109 width=0)
               Index Cond: ((speaker_name)::text = 'Seth Waxman'::text)
         ->  Bitmap Index Scan on index_statements_on_casefile_id  (cost=0.00..44.40 rows=2363 width=0)
               Index Cond: (casefile_id = ANY ('{12,563,876,4303,1120,422,654,13,988,335}'::integer[]))

仅通过speaker_name过滤:

EXPLAIN for: SELECT "statements".* FROM "statements"  WHERE (to_tsvector('simple', statement_text) @@ to_tsquery('simple', 'hello') and speaker_name in ('Seth Waxman'))
                                                        QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
 Index Scan using index_statements_on_speaker_name_and_person_role_id on statements  (cost=0.09..217.67 rows=1 width=247)
   Index Cond: ((speaker_name)::text = 'Seth Waxman'::text)
   Filter: (to_tsvector('simple'::regconfig, statement_text) @@ '''hello'''::tsquery)

任何帮助都将不胜感激。

0 个答案:

没有答案