我有一个包含大约 100 万个电话号码的表格和另一个包含大约 3000 个 ISD 代码(国家/地区代码)的表格。现在我想在最长前缀匹配上将电话号码与所有这些 ISD 代码进行匹配。 在 ISD 表中,我可以有例如:
1 US
1808 US (Hawaii)
如果电话号码现在是 1223244223,它应该返回美国,但如果是 1808322353,它应该返回美国(夏威夷)。 以最佳性能实现这一目标的最佳方法是什么?
这是我目前所拥有的。不幸的是对性能不满意,我想避免使用函数:
DELIMITER $$
CREATE DEFINER=`root`@`localhost` FUNCTION `isd`(telnum varchar(32)) RETURNS int(4)
BEGIN
RETURN (SELECT if(locate(isd, telnum)=1, (locate(isd, telnum)*length(isd)), 0) as score FROM tbl_ref_isd_v1 having score>0 order by score desc limit 1);
END
此外,我还有这个不同的功能,它似乎更快一些:
DELIMITER $$
CREATE DEFINER=`root`@`localhost` FUNCTION `isd_new`(telnum varchar(32)) RETURNS int(4)
BEGIN
RETURN (
select isd
from test.tbl_ref_isd_v1
where telnum like CONCAT(isd, '%')
order by length desc LIMIT 1
);
END
最佳答案
这是一个执行您想要的操作的查询:
select pn.*, max(ic.code)
from (select pn.*, ic.code, len(ic.code)
from PhoneNumbers pn join
ISDCodes ic
on pn.phonenumber like concat(ic.code, '%')
) pni
group by pn.phonenumber;
请注意,对于初始字符串,max()
有效,因为 1808
大于 1
,依此类推。
编辑:
在 ISDCodes(code)
上建立索引。那么以下应该可以正常工作:
select pn.*, coalesce(ic5.code, ic4.code, ic3.code, ic2.code, ic1.code) as code
from PhoneNumbers pn left outer join
ISDCodes ic1
on left(pn.phonenumber, 1) = ic1.code left outer join
ISDCodes ic2
on left(pn.phonenumber, 2) = ic2.code left outer join
ISDCodes ic3
on left(pn.phonenumber, 3) = ic3.code left outer join
ISDCodes ic4
on left(pn.phonenumber, 4) = ic4.code left outer join
ISDCodes ic5
on left(pn.phonenumber, 5) = ic5.code;
您需要连接到更长的 ic.code
。
关于MySQL 最长前缀匹配 100 万条记录与 3000 种可能性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22134640/