2011-07-15 14 views
3

処理に時間がかかるmySQLクエリがあります。 url_clickテーブルの各IPの発信元を検出するために、国コードに関連するIP範囲の大きなテーブルを照会しています。 (IPデータベースからのhxxp://ip-to-country.webhosting.info/)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にクエリの 'EXPLAIN'を依頼すれば、何が得られますか? – marnir

+0

ありがとうございます。私はQuassnoiのインデックス作成の提案を試みましたが、何らかの理由でbツリーストレージタイプを作成できませんでした。私はその後、ジョナサン・レフラーの提案を試みましたが、これはクエリーから秒をずらしましたが、それでも時間がかかりました。私は、質問を投稿するのではなく、最初の記録エントリの時点でIPに関連する国に問い合わせることに決めました。 – Damo

答えて

0

2つのテーブル間の結合内の関数の使用が参加し、通常よりも遅くなるだろう、あなたはおそらくしたいので、その特定の操作を可能な限り延期する。だから、私はデータを要約し、それに参加したい:

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; 

スキーマを再設計することができますし、この分析をたくさんやってしようとしている場合は、doesnの条件に参加するように二つのテーブルのいずれかを手直しINET_ATON()を使用する必要はありません。

おそらく、url_id列にインデックスがあります。それはあなたに多くの利益を与える唯一のものです。

0

IPアドレスは、構造、あなたはおそらくその構造を尊重し、あなたのgeo_ipテーブルに持っていた範囲のようなツリーを持っています。

IPが193.167で始まる場合、193.167の部分範囲に関連する行だけが操作されるようにgeo_ipテーブルを非常に迅速にフィルタリングするための索引が必要です。

このアプローチでは、応答時間を大幅に改善できるはずです。

私は、これはINET_ATONは私に少しだけ心配ことあなたに

0

を助けることを願っています。 ip_addr列のインデックスは無用になります。情報をすべて同じ形式にする方法があれば、データをDBに入れる前に数値に変換しておくと役立つかもしれません。

これ以外にも、インデックスの賢明な使用に関する標準的なアドバイスが適用されます。 ipfromiptoのインデックス、および/またはurl_idのインデックスが必要な場合があります。

0

MySQLこのようなクエリは最適化されません。あなたは、このようにそれらの上R-Treeインデックスを構築することができ、LineStringsにあなたのipfrom-ipto範囲を変換する必要があります

は:

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_ipMyISAMテーブルでなければなりません。

は、詳細についてはこちらをご覧ください:

関連する問題