2011-07-15 29 views
3

我有一個需要很長時間來處理的mySQL查詢。我正在查詢與國家/地區代碼相關的IP範圍大表,以查找url_click表中每個IP的原始國家/地區。 (來自hxxp://ip-to-country.webhosting.info/的IP數據庫)我的mySQL查詢效率如何?

雖然速度很慢,但它的效果非常出色。

有沒有更有效的方法來寫這個查詢?

表和輸出JPG:http://tiny.cx/a4e00d

SELECT ip_addr AS IP, geo_ip.ctry, count(ip_addr) as count 
FROM `admin_adfly`.`url_click`,admin_adfly.geo_ip 
WHERE INET_ATON (ip_addr) 
BETWEEN geo_ip.ipfrom AND geo_ip.ipto 
AND url_id = 165 
GROUP BY ip_addr; 
+1

我可以推薦http://codereview.stackexchange.com這種事情嗎? –

+2

我懷疑過濾INET_ATON()列上的結果意味着它必須掃描應用INET_ATON()到'url_id = 165'的所有內容 - 你能否預先寫入'INET_ATON()'你的以某種方式解決問題,作爲專欄?另外,你有一個關於url_id的索引嗎?另外,如果你要求MySQL'查詢'查詢,你會得到什麼? – marnir

+0

謝謝大家。我試過Quassnoi建議創建一個索引,但由於某種原因,我無法創建一個b-tree存儲類型。然後我嘗試了喬納森·萊弗勒的建議,這確實爲查詢減少了幾秒鐘,但它仍然需要很長時間。我決定在初始記錄輸入點而不是後期查詢中查詢與IP相關的國家。 – Damo

回答

0

兩個表之間的連接使用功能的將是比正常的加入更慢,所以你可能要儘可能推遲特定的操作。所以,我想總結的數據,然後加入吧:

SELECT S.IP_Addr, G.Ctry AS Country, S.Count 
    FROM (SELECT ip_addr, COUNT(ip_addr) AS Count 
      FROM admin_adfly.url_click 
     WHERE url_id = 165 
     GROUP BY ip_addr) AS S 
    JOIN admin_adfly.geo_ip AS G 
    ON INET_ATON (ip_addr) BETWEEN geo_ip.ipfrom AND geo_ip.ipto; 

如果可以重新設計架構,並會做很多這樣的分析,返工兩個表之一,這樣的連接條件沒有按不需要使用INET_ATON()。

假設你有一個url_id列的索引;這是唯一一個能夠給你帶來很多好處的人。

0

IP地址具有相同的結構和你有你的geo_ip表最有可能尊重結構範圍內的樹。

如果您的IP以193.167開頭,那麼您應該有一個索引幫助您非常快速地過濾geo_ip表,以便僅操縱與193.167子範圍相關的行。

我認爲你應該能夠通過這種方法顯着提高響應時間。

我希望這將有助於你

0

INET_ATON我擔心只是有點。它會使ip_addr列中的任何索引都無用。如果你有一種將信息全部放入同一格式的方法,比如說在將數據放入數據庫之前將其轉換爲數字,這可能會有所幫助。

除此之外,適用有關合理使用索引的標準建議。您可能需要索引ipfromipto,和/或url_id列。

0

MySQL不會優化這樣的查詢。

您將需要您的ipfrom-ipto範圍轉換成LineStrings,從而使他們在建立一個R-Tree指數:

ALTER TABLE 
     geo_ip 
ADD  range LINESTRING; 

UPDATE geo_ip 
SET  range = LINESTRING(POINT(-1, ipfrom), POINT(1, ipfrom)); 

ALTER TABLE 
     geo_ip 
MODIFY range LINESTRING NOT NULL; 

CREATE SPATIAL INDEX 
     sx_geoip_range 
ON  geo_ip (range); 

SELECT ip_addr AS IP, geo_ip.ctry, COUNT(*) 
FROM `admin_adfly`.`url_click` 
JOIN admin_adfly.geo_ip 
ON  MBRContains 
       (
       Point(0, INET_ATON (ip_addr)), 
       range 
       ) 
WHERE url_id = 165 
GROUP BY 
     ip_addr 

geo_ip應該是一個MyISAM表。

在這裏看到更多的細節: