在长文本字段上使用PostgreSQL trigram进行慢速模糊搜索

n7taea2i  于 5个月前  发布在  PostgreSQL
关注(0)|答案(1)|浏览(74)

我看到了缓慢的查询(~20秒)当我在PostgreSQL中对一个相对较小的记录集(8 k)执行模糊文本搜索时。我已经设置了GIN和GIST三元组索引,并通过ANALYZE确认它们正在使用。性能似乎是由少数具有非常长的文本字段的记录驱动的。虽然大多数记录都在2k字符以下,大约200个超过10 k,少数超过20 k。将这些长字符串截断为10 k字符将查询时间降低到8 s。
我试过PostgreSQL 10和11,GIN和GIST索引,在性能上没有实质性的变化。
我尝试将文本内容拆分为大量的记录,每条记录都要小得多,在多条记录中搜索相同的文本会导致亚秒级的查询。
这个问题完全不值得注意:

select title, 
'orthopedic surgeon' <<-> content as sml
from answers
where 'orthopedic surgeon' <% content
order by sml desc

字符串
对于这么少的记录,我希望三元组索引能提供近乎即时的结果,即使我的文本字段有30 k+字符。我不希望通过将内容拆分到更多记录来加快查询速度。这种性能正常吗?

bybem2ql

bybem2ql1#

很明显,我很晚才谈到这个问题,但我也遇到了类似的问题,而你关于拆分文本会有更好的性能的观察使它成为现实。
三元组索引的工作原理是在目标文档中查找搜索字符串的位。这部分速度非常快。因此,如果您正在搜索“gold星星”,它将立即找到包含每个三元组“gol”,“old”,“ld“,“d s”,“st”,“sta”和“tar”的所有记录。
然而,并不能保证三元组的顺序是正确的。也许你有一条记录,上面写着“golly的老星星”--它有索引要找的所有东西,但它实际上并不包含“gold星星”。所以,在确定了一组候选记录之后,Postgres现在必须扫描每个候选文本,以验证所需的文本实际上存在于所需的序列中。这部分只是一个普通的旧文本扫描,在整个记录中查找,直到找到文本(或找不到)。
因此,您希望让此过程的第一步--索引部分--完成尽可能多的工作。如果您有一个10,000个字符的记录,其中搜索字符串出现两次,并且您没有将其拆分,那么Postgres将不得不扫描(平均)3,333个字符,然后它确认子串存在。如果你把它分成100个100个字符的子记录,索引将删除其中的98个,Postgres平均只需扫描100个字符,将操作速度提高了33倍。
(可能还有更多的东西--我怀疑Postgres中有一些优化,只适用于特定的文本长度--但这肯定是其中的一部分。

相关问题