2016-02-01 43 views
3

我看起來像這樣的兩個表:有效地連接(和更新)的表按值到最小值/最大值範圍

    IpNumbers 
+----------+----------+-----------------------+ 
|____min___|____max___|__correspondingCountry_| 
|   |   |      | 
| 0  | 10  |  Australia  | 
| 11 | 20  |   US   | 
| 21 | 30  |   Taiwan  | 
|____31____|___40_____|_________Canada________| 



        Users 
+----------+----------+----------------+ 
|__userId__|__ipNumber__|____country___| 
| 1  |  6  |    | 
| 2  |  13  |    | 
| 3  |  7  |    | 
|____4_____|_____21_____|______________| 

有IpNumbers表,其具有從IP地址derrived一個數字 - 這對應於IP地址所屬的某個國家。例如,如果IP號碼在11 and 20之間,那麼具有該IP地址的用戶來自美國(US)。

我的問題:我在Users表約60,000個用戶 - 用戶每一個都有與之相關的IP號碼。我也有IpNumbers表,其中有大約4,000,000條Ip數字與國家的記錄。

什麼是最有效的SQL查詢我可以構造一個國家分配給在Users表中的每個用戶?多長時間我可以期待查詢完成?

注:我已經收錄在ipNumbersminmax列,我也收錄在UsersuserId列。 userId字段也是獨一無二的。

編輯:ipNumber在users表也是衍生整數值

+0

是在'Users'還派生整數值'ipNumber'列,或者是它的IPv4點四1.2.3.4?請發佈兩個表的「SHOW CREATE TABLE tablename」輸出。 –

+0

。我還明白,你想直接與每個用戶存儲的國家,而不是基於用戶的'ipNumber'值在運行時查詢呢?這導致了非規範化。 –

+0

@MichaelBerkowski - yes用戶表中的ipNumber也是派生的整數。是的 - 我想直接與每個用戶存儲每個國家。該查詢不會在運行時運行。 – user1775598

回答

2

這是一個相當普遍的問題。我認爲最好的方法是從IpNumbers(min, max, corresponding_country)索引開始。 (最後一列不是絕對必要的)。

然後,您可以使用下面的查詢:

select u.*, 
     (select ipn.corresponding_country 
     from IpNumbers ipn 
     where ipn.min <= u.ipNumber 
     order by ipn.min desc 
     limit 1 
     ) as corresponding_country 
from users u; 

這應該使用指數爲whereorder by。但是,它不驗證結束條件。如果您需要,您可以使用相同的邏輯獲取max,然後進行比較以查看IP地址是否在範圍內。

+0

@ user2864740。 。你可以嘗試使用額外的約束'和ipn.max <= u.ipNumber'。在某種程度上,我一定發現那阻礙了索引的使用。但是,如果它起作用,那就使用它! –

+0

我很慣壞[不MySQL的],我常常忘記有關具體情況的細節:由ipn.min極限1} – user2864740

+0

是u.ipNumber> = ipn.min訂單?我迷茫min> = ipNumber,爲什麼min> = ipNumber? –

0

嘗試如下:

SELECT u.USERID, u.IPNUMBER, i.CorrespondingCOUNTRY FROM USERS u, IPNUMBERS i 
WHERE u.IPNUMBER BETWEEN i.MIN AND i.MAX 
/