【问题标题】:PostgreSQL full text search not using index after importing data with COPY使用 COPY 导入数据后,PostgreSQL 全文搜索不使用索引
【发布时间】:2013-09-04 10:18:49
【问题描述】:

我正在尝试让 PostgreSQL 使用索引来使用全文搜索进行前缀搜索。它通常工作正常,但前提是我在导入数据后创建索引。也许这是某种预期的行为,但我不明白。

首先我创建索引,然后使用 COPY 命令导入数据:

CREATE INDEX account_fts_idx ON account
    USING gin(to_tsvector('german', remote_id || ' ' || name || ' ' || street || ' ' || zip || ' ' || city ));
COPY account (id, remote_id, name, street, zip, city ...) FROM '/path/account.csv' WITH DELIMITER ',' CSV;

然后我使用以下 select 语句运行 PREFIX(也许这很重要)搜索:

EXPLAIN ANALYZE SELECT a.id, a.remote_id, a.name, a.street, a.zip, a.city, al.latitude, al.longitude 
FROM account a 
LEFT JOIN account_location al ON al.id = a.id 
WHERE (to_tsvector('german', a.remote_id || ' ' || a.name || ' ' || a.street || ' ' || a.zip || ' ' || a.city) 
@@ (to_tsquery('german', 'hambu:*')))

这会导致性能不佳,因为没有使用索引:

Hash Left Join  (cost=28.00..3389.97 rows=319 width=94) (actual time=1.685..1237.674 rows=1336 loops=1)
  Hash Cond: (a.id = al.id)
  ->  Seq Scan on account a  (cost=0.00..3360.73 rows=319 width=78) (actual time=1.665..1236.589 rows=1336 loops=1)
        Filter: (to_tsvector('german'::regconfig, (((((((((remote_id)::text || ' '::text) || (name)::text) || ' '::text) || (street)::text) || ' '::text) || (zip)::text) || ' '::text) || (city)::text)) @@ '''hambu'':*'::tsquery)
  ->  Hash  (cost=18.00..18.00 rows=800 width=24) (actual time=0.001..0.001 rows=0 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 0kB
        ->  Seq Scan on account_location al  (cost=0.00..18.00 rows=800 width=24) (actual time=0.001..0.001 rows=0 loops=1)
Total runtime: 1237.928 ms

现在出现了奇怪的部分:如果我删除索引并使用相同的 CREATE INDEX 命令重新创建它,相同的 SELECT 查询会使用索引并且速度非常快。

Hash Left Join  (cost=61.92..1290.73 rows=1278 width=94) (actual time=0.561..1.918 rows=1336 loops=1)
  Hash Cond: (a.id = al.id)
  ->  Bitmap Heap Scan on account a  (cost=33.92..1257.78 rows=1278 width=78) (actual time=0.551..1.442 rows=1336 loops=1)
        Recheck Cond: (to_tsvector('german'::regconfig, (((((((((remote_id)::text || ' '::text) || (name)::text) || ' '::text) || (street)::text) || ' '::text) || (zip)::text) || ' '::text) || (city)::text)) @@ '''hambu'':*'::tsquery)
        ->  Bitmap Index Scan on account_fts_idx  (cost=0.00..33.60 rows=1278 width=0) (actual time=0.490..0.490 rows=1336 loops=1)
              Index Cond: (to_tsvector('german'::regconfig, (((((((((remote_id)::text || ' '::text) || (name)::text) || ' '::text) || (street)::text) || ' '::text) || (zip)::text) || ' '::text) || (city)::text)) @@ '''hambu'':*'::tsquery)
  ->  Hash  (cost=18.00..18.00 rows=800 width=24) (actual time=0.001..0.001 rows=0 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 0kB
        ->  Seq Scan on account_location al  (cost=0.00..18.00 rows=800 width=24) (actual time=0.001..0.001 rows=0 loops=1)
Total runtime: 2.054 ms

那么为什么要在导入后创建索引呢?

对我来说更重要的是:新行(通常通过 INSERT INTO 添加)是否会添加到索引中?

【问题讨论】:

  • 您是否在导入数据后运行了分析?
  • 不,我没有这样做,遗憾的是这样做无济于事,但它为我指明了正确的方向。我必须运行“分析帐户”,根据文档“完成任何待处理的索引插入”(对于 GTIN 索引)。这有帮助,谢谢!

标签: postgresql indexing full-text-search


【解决方案1】:

@Denis 为我指明了正确的方向。我查看了 VACUUM, ANALYZE 命令并找到了解决方案:

对于具有 GIN 索引的表,VACUUM(以任何形式)还通过将挂起的索引条目移动到主 GIN 索引结构中的适当位置来完成任何挂起的索引插入。 (PostgreSQL Documentation: VACUUM)

在运行VACUUM account 之后,SELECT 查询使用预期的索引。

【讨论】:

    猜你喜欢
    • 2018-07-22
    • 1970-01-01
    • 2014-09-09
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多