我有两张大桌子,我需要将它们拼在一起。匹配不应该是明确的比较。我使用了 trigrams、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);
遗憾的是,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。