1

这是我在处理各种不同数据集的工作中经常出现的问题,所以请原谅我笼统地介绍它,而不是使用具体的例子。

我经常需要从一个大表(通常为数百万行)中获取记录,其中一个文本列类似于一个小得多的表(10 到 100 行)中的列。我目前的做法如下,targets小表在哪里matches,大表在哪里。

set pg_trgm.similarity_threshold = .9;

select *
from targets as t
inner join matches as m on
  t.name % m.name;

matches.name将具有 GIN 索引,并且通常具有相对较高的唯一性,可能有 10-20% 的记录是重复的。两者matches.nametargets.name几乎总是少于 50 个字符,而且通常短得多。

据我了解,这是一个稍微不寻常的用例:Postgres 文档和大多数 SO 答案似乎都集中在优化以匹配单个值。所以我很想听听关于两个问题的想法:

  1. 笼统地说(几十分钟、几小时等),并假设数据库配置得最优化,就性能而言,这种类型的查询的合理目标是什么,例如,给定 300 个目标和 3 亿个潜在匹配项?
  2. 在给定参数的情况下,我目前使用的策略是最有效的策略吗?例如,是否值得尝试使用 GiST 索引并使用运算符获取每行的前n 个匹配项<->?是否有完全不同的方法可以更有效?

在此先感谢您的帮助!

4

2 回答 2

0

不管你怎么做,它都会很慢,除非targets很小。

连接必须是嵌套循环连接,因为=连接条件中没有。执行时间会随着行数线性增长targets

于 2020-11-26T11:23:40.693 回答
0

这种性质的批量操作没有任何好处。他们不会说要做不止一次,因为没什么可说的。执行 300 次(t 中的行)大约是 t 中执行一行的 300 倍。

这将取决于三元组频率的直方图,因此如果这些是街道地址或英语短语或序列号/零件号或什么,它会产生很大的不同。作为一个粗略的估计,我会说(在 0.9 的阈值下,随着阈值的降低,它会变得更糟)你在 t 中看到每行 30 秒到一分钟。

我预计使用 GiST 而不是 GIN 会大幅下降。

一种更有效的方法是用 C 手工编写一些不必处理事务、可变性、并发性、抽象数据类型等的东西。如果我们对频率进行统计估计,也可能会做出一些改进巨型表中的每个三元组,但我认为这对于当前 PostgreSQL 基础架构中的扩展来说不太可行。

于 2020-11-27T17:07:26.140 回答