【问题标题】:How to optimize this Levenshtein distance calculation如何优化这个 Levenshtein 距离计算
【发布时间】:2013-01-15 00:10:50
【问题描述】:
Table a 大约有 8,000 行,table b 大约有 250,000 行。如果没有 levenshtein 函数,查询只需不到 2 秒。包含该功能大约需要 25 分钟。
SELECT
*
FROM
library a,
classifications b
WHERE
a.`release_year` = b.`year`
AND a.`id` IS NULL
AND levenshtein_ratio(a.title, b.title) > 82
【问题讨论】:
标签:
mysql
levenshtein-distance
【解决方案1】:
您提供的信息太少,无法真正帮助您。
1) 我的第一个猜测是尝试创建其他 WHERE 条件来减少要扫描的行数。
2) 如果这是不可能的...鉴于表库和分类中的标题是已知的,一个想法是创建一个表,其中所有数据都已按如下方式计算:
TABLE levenshtein_ratio
id_table_library
id_table_classifications
precalculated_levenshtein_ratio
因此您将使用此查询填充表:
insert into levenshtein_ratio select a.id, b.id, levenshtein_ratio(a.title, b.title) from library, classifications
然后您的查询将是:
SELECT
*
FROM
library a LEFT JOIN
classifications b ON a.`release_year` = b.`year`
LEFT JOIN levenshtein_ratio c ON c.id_table_library = a.id AND c.id_table_classifications = b.id
WHERE
a.`id` IS NULL
AND precalculated_levenshtein_ratio > 82
这个查询可能不会超过原来的 2 秒。
此解决方案的问题在于表 a 和 b 中的数据可能会更改,因此您需要创建一个触发器以使其保持更新。
【解决方案2】:
更改您的查询以使用正确的连接(语法自 1996 年以来一直存在)。
此外,您的所有 levensrein 条件都可以移动到连接条件中,这应该会给您带来性能优势:
SELECT *
FROM library a
JOIN classifications b
ON a.`release_year` = b.`year`
AND levenshtein_ratio(a.title, b.title) > 82
WHERE a.`id` IS NULL
另外,请确保 b.year 上有一个索引:
create index b_year on b(year);
【解决方案3】:
我假设levenshtein_ratio 是您编写的函数(或者可能包含在其他地方)。如果是这样,数据库服务器将无法在使用索引的正常意义上对其进行优化。所以这意味着它只需要为其他连接条件产生的每条记录调用它。对于内部联接,对于这些表大小(最大为 8000*250000 = 20 亿),这可能是一个非常大的数字。您可以使用以下命令检查需要调用的总次数:
SELECT
count(*)
FROM
library a,
classifications b
WHERE
a.`release_year` = b.`year`
AND a.`id` IS NULL
这是对它为什么慢的解释(并不是对如何优化它的问题的真正答案)。要对其进行优化,您可能需要在连接条件中添加额外的限制因素,以减少对用户定义函数的调用次数。