2014-03-02 34 views
2

我有一张大约有100万个电话号码的表格,另一个表格大约有3000个ISD码(国家/地区代码)。现在我想匹配所有这些ISD代码上最长的前缀匹配的电话号码。 在ISD表我可以有例如:MySQL最长的前缀与1000个记录中的3000个可能性匹配

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 

回答

1

这里是一个查询,做什么你想:

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()作品因为18081大,等等。

我应该加上。这完成了工作。它不一定是最高性能的,但这取决于很多因素,并且StackOverflow可能不是这种问题的最佳位置。

编辑:

建立在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

+0

你的逻辑正在工作,但非常缓慢(在80k vs 3700 isd代码的小记录集上> 80s)。相比于需要0.2s的功能。不幸的是,函数不会返回来自isd表的整个行(我更喜欢)。 –

+0

第二个查询要快得多(也比函数快)。现在有一种独立于ISDCode长度的方法吗?我有从1到9位数字的代码。我将额外的连接添加到了9个,但是我想知道我们是否能够以相同的性能实现这种动态。 对于我从ISDCodes表中获得的所有其他字段,我是否总是需要使用coalesce,还是有更好的方法? –

+0

@DavidLaroche。 。 。我不认为你可以使这个动态,并仍然有查询使用基本的SQL索引。你可以用'prepare'语句来做到这一点。 –