0

ユーザー情報を含むテーブルと地理位置情報データを含むテーブル (GeoIP のデータベースから) を相互参照しようとすると問題が発生します。

ユーザー テーブルには標準形式 (整数ではない) の IP アドレスがあり、GeoIP テーブルには整数の IP 範囲を持つ GeoIP データがあります。

このクエリは機能しますが、非常に遅く、最適化されていません。

SELECT email, country 
FROM users 
INNER JOIN geoip ON users.ip BETWEEN geoip.startip AND geoip.endip

ここで非常に簡単なものが欠けているように感じます。

更新: このクエリは機能しますが、非常に遅いです。高速化するためにインデックスを作成する方法はありますか? 現在、いつ実行されても、各行の実行には約 300 ~ 500 ミリ秒かかりますが、これは遅すぎます。

SELECT email, country 
FROM users INNER JOIN geoip ON INET_ATON(users.ip) 
BETWEEN geoip.startip AND geoip.endip

ありがとう!

更新 2: クエリの EXPLAIN 出力は次のとおりです。

+----+-------------+-----------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows     | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+----------+-------------+
|  1 | SIMPLE      | geoip     | ALL  | NULL          | NULL | NULL    | NULL |  3651972 |             | 
|  1 | SIMPLE      | users     | ALL  | NULL          | NULL | NULL    | NULL | 87996123 | Using where | 
+----+-------------+-----------+------+---------------+------+---------+------+----------+-------------+

DB が使用中で、9,000 万行を超えているため、現時点では整数のみの IP 行を追加できません。ダウンタイム中に行うことを検討することになりますが、今のところ、この方法で実行したいと考えています。

4

1 に答える 1

2

まだコメントできないので、ここに「答え」があります...

確実に機能しますか?私があなたの説明を正しく理解していれば、users.ip は char または varchar の CIDR 表記であり、geoip.startip/endip は整数です。そのため、このクエリではこれら 2 つを正しく比較する方法がありません。

これを行う正しい方法は次のいずれかです

SELECT email, country 
FROM users INNER JOIN geoip ON INET_ATON(users.ip) 
BETWEEN geoip.startip AND geoip.endip

また

SELECT email, country 
FROM users INNER JOIN geoip ON users.ip 
BETWEEN INET_NTOA(geoip.startip) AND INET_NTOA(geoip.endip) 

どちらのテーブルが大きいか (より多くの行) に応じて、どちらがより良いものになります。

ただし、これを行う最善の方法は、users.ip を整数 (または整数解釈の別の列) として格納することです。

于 2011-12-06T23:16:03.173 に答える