2014-03-02 72 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'語句來做到這一點。 –