【问题标题】:Matching a small table (<1,000 rows) to a large table (>100m rows) using pg_trgm—most efficient method?使用 pg_trgm 将小表(<1,000 行)与大表(>100m 行)匹配——最有效的方法?
【发布时间】:2021-03-09 04:55:50
【问题描述】:

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

我经常需要从一个大表(通常有数百万行)中获取记录,其中文本列类似于小得多的表(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 索引并使用 &lt;-&gt; 运算符为每一行获取顶部的 n 匹配项?有没有可能更有效的完全不同的方法?

提前感谢您的帮助!

【问题讨论】:

    标签: postgresql fuzzy-search postgresql-12 pg-trgm


    【解决方案1】:

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

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

    我预计使用 GiST 而不是 GIN 会大大降低性能。

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-04
        相关资源
        最近更新 更多