GIN索引出了什么问题,无法避免SEQ扫描?

dai*_*isy 5 postgresql gwt-gin full-text-search

我创建了一个这样的表,

create table mytable(hash char(40), title varchar(500));
create index name_fts on mytable using gin(to_tsvector('english', 'title'));
CREATE UNIQUE INDEX md5_uniq_idx ON mytable(hash);
Run Code Online (Sandbox Code Playgroud)

当我查询标题时,

test=# explain analyze select * from mytable where to_tsvector('english', title) @@ 'abc | def'::tsquery limit 10;
                                                     QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.00..277.35 rows=10 width=83) (actual time=0.111..75.549 rows=10 loops=1)
   ->  Seq Scan on mytable  (cost=0.00..381187.45 rows=13744 width=83) (actual time=0.110..75.546 rows=10 loops=1)
         Filter: (to_tsvector('english'::regconfig, (title)::text) @@ '''abc'' | ''def'''::tsquery)
         Rows Removed by Filter: 10221
 Planning time: 0.176 ms
 Execution time: 75.564 ms
(6 rows)
Run Code Online (Sandbox Code Playgroud)

不使用索引。有任何想法吗?我有 10m 行。

Lau*_*lbe 2

你的索引定义有错字,应该是

ON mytable USING gin (to_tsvector('english', title))
Run Code Online (Sandbox Code Playgroud)

代替

ON mytable USING gin (to_tsvector('english', 'title'))
Run Code Online (Sandbox Code Playgroud)

按照您编写的方式,它是一个常量,而不是一个索引字段,这样的索引对于您执行的搜索确实毫无用处。

要查看是否可以使用索引,可以执行

SET enable_seqscan=off;
Run Code Online (Sandbox Code Playgroud)

然后再次运行查询。
如果仍然没有使用该索引,则该索引可能无法使用。

除了上述内容之外,您的执行计划还有一些让我觉得奇怪的地方。PostgreSQL 估计顺序扫描mytable将返回 13744 行,而不是您所说的 1000 万行。您是否禁用了 autovacuum 或者是否有其他原因可能导致您的表统计信息不准确?