【问题标题】:Perfomance for join table with string comparison带有字符串比较的连接表的性能
【发布时间】:2021-10-13 03:49:35
【问题描述】:

我有两张大桌子,我需要把它们放在一起。匹配不应该是一个明确的比较。我使用了三元组,Levenshtein 的公式,但我的表现很差。也许有人可以帮助提高性能。 A表大小约20万行,B表大小约60万行。

   CREATE TABLE TBL_A(NAME VARCHR,SURNAME VARCHAR, BIRTH_DATE DATE, TABLE_B_ID INT4);
   CREATE TABLE TBL_B(ID INT4, NAME VARCHR, SURNAME VARCHAR, BIRTH_DATE DATE);
--variant 1
SET pg_trgm.similarity_threshold = 0.8; 
UPDATE TBL_A A SET TABLE_B_ID = B.ID
FROM TBL_B B
WHERE A.NAME % B.NAME
AND A.SURNAME % B.SURNAME
AND ABS(A.BIRTH_DATE ::DATE - B.BIRTH_DATE ::DATE)<=1 
--variant 2
UPDATE TBL_A A SET TABLE_B_ID = B.ID
FROM TBL_B B
WHERE A.NAME = B.NAME
AND A.SURNAME = B.SURNAME
AND ABS(A.BIRTH_DATE ::DATE - B.BIRTH_DATE ::DATE)<=1   
--variant 3
UPDATE TBL_A A SET TABLE_B_ID = B.ID
FROM TBL_B B
WHERE levenshtein_less_equal (A.NAME ,B.NAME,2)<=2
AND levenshtein_less_equal (A.SURNAME ,B.SURNAME,2)<=2 
AND ABS(A.BIRTH_DATE ::DATE - B.BIRTH_DATE ::DATE)<=1 

所有这些选项的性能都很差(大约 7 小时)。我尝试创建索引,但速度并没有提高

CREATE INDEX ind_a_name ON TBL_A USING gist(NAME  trm_gist_ops);
CREATE INDEX ind_a_Surname ON TBL_A USING gist(SURNAME  trm_gist_ops);

【问题讨论】:

  • 这看起来是一次性的。就算真的花了7个小时,既然已经完成了,为什么还要重新运行呢?
  • 我希望 gin_trgm_ops 在这里比第一个变体的 gist_trgm_ops 快得多。
  • 这将是不同对表的常规过程
  • 我应该在两个表上创建 gin 索引吗?
  • 这两者都应该给你一个提升,但我认为在 TBL_B 上使用它似乎比在 TBL_A 上使用它更自然。

标签: postgresql query-optimization levenshtein-distance metaphone


【解决方案1】:

很遗憾,Levenshtein 距离比较无法编入索引。每个比较都是两个输入字符串的函数。

通常通过使用消除大多数比较的两阶段 where 子句来解决这类问题,然后应用 Levenshtein 的字符串距离函数。

你能设计一个单射函数f(name) 来产生name 的某种签名吗?举个简单的例子,它可以从名称中删除元音。 SOUNDEX() 就是这样一个函数,但它真的很粗糙,只适用于北美名称。 Metaphone 是一个类似的函数。 (想出这些功能的人都是会说英语的人。)

如果你这样做,那么你可以用

填充你的表
   name, signature_name

(signature_name, name) 上放置一个索引,并使用这个 WHERE 过滤器。

 WHERE A.signature_name = B.signature_name
   AND levenshtein_less_equal (A.name,B.name,2)<=2

诀窍:使用索引列进行大部分比较工作,并且仅在您已经知道匹配非常接近时才使用 Levenshtein。

【讨论】:

  • 感谢您的回复。你有任何关于 ts_vectors 的经验吗?也许会更好?
  • 在 (signature_name, name) 上放一个索引,然后使用这个 WHERE 过滤器 -- btree ?
  • 我建议的那种函数可以很好地与 BTREE 配合使用。但是该函数的结果仅在相等性方面具有可比性,而不是在价值方面。 (也就是说,说sig1 &gt;= sig2 - 2 或类似的东西是没有意义的。)所以另一个索引组织(哈希)也可以工作。
  • 要询问ts_vector的使用,最好再问一个问题。请包括一些示例数据和所需的结果。对于它的价值,ts_* 函数最适合包含多个单词而不是单个单词的文档(列)。
猜你喜欢
  • 2020-06-26
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
  • 1970-01-01
  • 2011-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多