5

我有一个包含大约 1 亿行的表格和一个要搜索的文本字段。我想出了两种方法来做到这一点,我想知道每种方法的性能影响。

方法 1: 这是我在网上看到的每篇博文都推荐的方法(例如12。)。这个想法是用一ts_vector列扩充表并索引新列。
一个简单的例子是:

CREATE TABLE articles (
    id_articles BIGSERIAL PRIMARY KEY,
    text TEXT,
    text_tsv TSVECTOR
);
CREATE INDEX articles_index ON articles USING gin(text_tsv);

然后使用触发器来确保texttext_tsv列保持最新。
然而,这对我来说似乎很浪费,因为现在TSVECTOR信息必须同时存储在表和索引中,并且数据库变得更加复杂。所以我想出了第二种方法。

方法2: 我的想法是去掉多余的列,直接把索引改成包含to_tsvector函数,像这样:

CREATE TABLE articles (
    id_articles BIGSERIAL PRIMARY KEY,
    text TEXT
);
CREATE INDEX articles_index ON articles USING gin(to_tsvector(text));

问题:使用方法 2 比方法 1 有什么缺点吗?

对于我的特定数据库,我使用了第二种方法,并且对于单个单词的简单查询,我似乎获得了合理的加速(搜索大约需要 1 秒)。但是,当我在函数中有多个&|运算符的复杂查询to_tsquery(并且表中只有约 10 个匹配结果)时,搜索需要永远运行(好几个小时)。如果我切换到方法 1,由于某种原因,我可能会看到更快的查询时间吗?

如果我的查询性能缓慢不是由于我选择了方法 2,我还能做些什么来加快使用 构建的复杂查询to_tsquery吗?

我正在使用 postgresql 10.10。

4

1 回答 1

7

不存储 tsvector 的缺点是必须从原始文本中重新计算 tsvector,以便“重新检查”该行是否满足查询。这可能非常缓慢。

如果候选匹配位图的大小溢出 work_mem,则需要重新检查。对于某些运算符,总是需要重新检查,例如短语匹配运算符<->,<2>等。

于 2020-01-16T04:23:41.617 回答