2015-05-21 106 views
0

我想找到一種方法來提高我的mysql表中包含IP範圍的性能(它將有高達500個SELECT查詢每秒(!)在高峯時間,所以我有點擔心)。mysql表性能升級(索引

我有這樣的結構的表:

id smallint(5) Auto Increment 
ip_start char(16)  
ip_end char(16) 

編碼utf8_general_ci(對整個表和除ID每列),表是MyISAM數據(僅SELECT查詢,沒有插入刪除此處需要/)的類型。此表的索引是PRIMARY id

在這個Momen桌上有近2000行。所有這些都包含ip的範圍。 例如:

ip_start 128.6.230.0 
ip_end 128.6.238.255 

當用戶來到一個網站我檢查,如果他的IP是在一些在我的表的範圍。我用這個查詢(DIBI SQL庫):

SELECT COUNT(*) 
FROM ip_ranges 
WHERE %s", $user_ip, " BETWEEN ip_start AND ip_end 

如果查詢的結果不爲零,則用戶的IP是在表的範圍之一 - 這是所有我需要做的。

我在想也許是把一些索引放在那張表上?但我不太確定它是如何工作的,如果它是一個好主意(因爲可能沒有什麼可以真正索引的,對吧?大多數IP範圍是不同的)。

我也有那些ip_start和ip_end列varchar類型,但我把它切換到只是字符(猜測其更快?)。

任何有關如何進一步改善此表/查詢的任何想法?

+0

它會幫助你,但你在比較STRINGS ...因爲ips不是真正的字符串,所以會很糟糕。 '10.0.0.0,101.0.0.0,9.9.9.9'是按照字符串順序遞增的,但它們絕對不是「數字」順序... –

+2

你可以在ip_start,ip_end上使用聚簇索引,但正如Marc所說的那樣在這裏使用字符串不是個好主意。您可以嘗試使用ip2int算法並使用整數比較代替 – bksi

+0

還有MySQL INET_ATON()AND INET_NTOA()函數。 https://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-aton和https://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions。 html#function_inet-ntoa – Uueerdo

回答

1

你不想使用聚合。相反,檢查是否有以下的回報任何行:

SELECT 1 
FROM ip_ranges 
WHERE %s", $user_ip, " BETWEEN ip_start AND ip_end 
LIMIT 1; 

LIMIT 1說,停在第一場比賽,所以它比較快。

對於此查詢,您需要索引ip_ranges(ip_start, ip_end)

當沒有匹配時,仍然存在性能問題。被測試的ip後的整個索引必須被掃描。我認爲以下應該是一個改進:

SELECT COUNT(*) 
FROM (SELECT i.start, ip_end 
     FROM ip_ranges i 
     WHERE %s", $user_ip, " >= ip_start 
     ORDER BY ip_start 
     LIMIT 1 
    ) i 
WHERE $user_ip <= ip_end; 

內部子查詢應該使用索引,但回退第一個匹配。外部查詢應該檢查範圍的結尾。這裏count(*)沒問題,因爲只有一行。

+0

謝謝,這應該會有很大幫助。 – Mordor