是否有任何理由在 postgres 表中而不是在索引中包含一个 `tsvector` 列?

Mik*_*cki 3 postgresql tsvector

我有一个包含大约 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);
Run Code Online (Sandbox Code Playgroud)

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

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

CREATE TABLE articles (
    id_articles BIGSERIAL PRIMARY KEY,
    text TEXT
);
CREATE INDEX articles_index ON articles USING gin(to_tsvector(text));
Run Code Online (Sandbox Code Playgroud)

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

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

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

我正在使用 postgresql 10.10。

jja*_*nes 6

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

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