我正在尝试使 postgres 全文搜索功能正常运行。
我有两个表,一个是我为测试创建的,另一个是我希望能够搜索的实际表:
测试表:
webarchive=# \d test_sites
Table "public.test_sites"
Column | Type | Modifiers
-------------+----------+---------------------------------------------------------
id | integer | not null default nextval('test_sites_id_seq'::regclass)
content | text |
tsv_content | tsvector |
Indexes:
"test_sites_pkey" PRIMARY KEY, btree (id)
"idx_test_web_pages_content" gin (tsv_content)
Triggers:
web_pages_testing_content_change_trigger AFTER INSERT OR UPDATE ON test_sites FOR EACH ROW EXECUTE PROCEDURE web_pages_testing_content_update_func()
“真实”表:
webarchive=# \d web_pages
Table "public.web_pages"
Column | Type | Modifiers
--------------+-----------------------------+--------------------------------------------------------
id | integer | not null default nextval('web_pages_id_seq'::regclass)
state | dlstate_enum | not null
errno | integer |
url | text | not null
starturl | text | not null
netloc | text | not null
file | integer |
priority | integer | not null
distance | integer | not null
is_text | boolean |
limit_netloc | boolean |
title | citext |
mimetype | text |
type | itemtype_enum |
raw_content | text |
content | text |
fetchtime | timestamp without time zone |
addtime | timestamp without time zone |
tsv_content | tsvector |
Indexes:
"web_pages_pkey" PRIMARY KEY, btree (id)
"ix_web_pages_url" UNIQUE, btree (url)
"idx_web_pages_content" gin (tsv_content)
"idx_web_pages_title" gin (to_tsvector('english'::regconfig, title::text))
"ix_web_pages_distance" btree (distance)
"ix_web_pages_distance_filtered" btree (priority) WHERE state = 'new'::dlstate_enum AND distance < 1000000
"ix_web_pages_priority" btree (priority)
"ix_web_pages_type" btree (type)
"ix_web_pages_url_ops" btree (url text_pattern_ops)
Foreign-key constraints:
"web_pages_file_fkey" FOREIGN KEY (file) REFERENCES web_files(id)
Triggers:
web_pages_content_change_trigger AFTER INSERT OR UPDATE ON web_pages FOR EACH ROW EXECUTE PROCEDURE web_pages_content_update_func()
除了额外的位,两者都有一个content
列,以及一个tsv_content
带有gin()
索引的列。tsv_content
每次修改列时,都会有一个触发器更新该列content
。
请注意,另一个 gin
索引工作正常,实际上我最初gin (to_tsvector('english'::regconfig, content::text))
在内容列上也有一个索引,而不是第二列,但是在等待该索引在测试中重建几次之后,我决定使用一个单独的列来预先存储 tsvector 值。
对测试表执行查询使用索引,就像我期望的那样:
webarchive=# EXPLAIN ANALYZE SELECT
test_sites.id,
test_sites.content,
ts_rank_cd(test_sites.tsv_content, to_tsquery($$testing$$)) AS ts_rank_cd_1
FROM
test_sites
WHERE
test_sites.tsv_content @@ to_tsquery($$testing$$);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on test_sites (cost=16.45..114.96 rows=25 width=669) (actual time=0.175..3.720 rows=143 loops=1)
Recheck Cond: (tsv_content @@ to_tsquery('testing'::text))
Heap Blocks: exact=117
-> Bitmap Index Scan on idx_test_web_pages_content (cost=0.00..16.44 rows=25 width=0) (actual time=0.109..0.109 rows=143 loops=1)
Index Cond: (tsv_content @@ to_tsquery('testing'::text))
Planning time: 0.414 ms
Execution time: 3.800 ms
(7 rows)
然而,对真实表的完全相同的查询似乎只会导致普通的旧顺序扫描:
webarchive=# EXPLAIN ANALYZE SELECT
web_pages.id,
web_pages.content,
ts_rank_cd(web_pages.tsv_content, to_tsquery($$testing$$)) AS ts_rank_cd_1
FROM
web_pages
WHERE
web_pages.tsv_content @@ to_tsquery($$testing$$);
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Seq Scan on web_pages (cost=0.00..4406819.80 rows=19751 width=505) (actual time=0.343..142325.954 rows=134949 loops=1)
Filter: (tsv_content @@ to_tsquery('testing'::text))
Rows Removed by Filter: 12764373
Planning time: 0.436 ms
Execution time: 142341.489 ms
(5 rows)
我已将我的工作内存增加到 3 GB 以查看是否是问题所在,但事实并非如此。
此外,应该注意的是,这些是相当大的表——大约 150GB 的文本跨越 400 万行(还有 800 万行,其中content
/tsv_content
是NULL
)。
该test_sites
表有 的 1/1000 行web_pages
,因为当每个查询都需要几分钟时进行试验有点令人望而却步。
我正在使用 postgresql 9.5(是的,我自己编译的,我想要ON CONFLICT
)。似乎还没有标签。
我已经通读了 9.5 的未决问题,我看不出这是任何问题的结果。
刚刚完全重建索引,问题仍然存在:
webarchive=# ANALYZE web_pages ;
ANALYZE
webarchive=# EXPLAIN ANALYZE SELECT
web_pages.id,
web_pages.content,
ts_rank_cd(web_pages.tsv_content, to_tsquery($$testing$$)) AS ts_rank_cd_1
FROM
web_pages
WHERE
web_pages.tsv_content @@ to_tsquery($$testing$$);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on web_pages (cost=10000000000.00..10005252343.30 rows=25109 width=561) (actual time=7.114..146444.168 rows=134949 loops=1)
Filter: (tsv_content @@ to_tsquery('testing'::text))
Rows Removed by Filter: 13137318
Planning time: 0.521 ms
Execution time: 146465.188 ms
(5 rows)
请注意,我实际上只是ANALYZE
编辑,并且禁用了 seqscan。
好吧,我花了一些时间在磁盘上腾出一些额外的空间,上面有数据库,将一些其他数据库移到另一个 SSD 上。
然后我跑遍
VACUUM ANALYZE
了整个数据库,现在显然它注意到我有索引。我之前只对这张表进行了分析和吸尘,但显然以某种方式进行一般性分析而不是对特定表进行分析会有所不同。去搞清楚。
VACUUM FULL;
既然我有足够的空间来处理,我也借此机会运行了一个。由于我在开发过程中一直在进行试验,所以我在表中遇到了一些行混乱,我想尝试合并由此产生的任何文件碎片。