IP地理位置查询太慢

Posted

技术标签:

【中文标题】IP地理位置查询太慢【英文标题】:IP geolocating query too slow 【发布时间】:2016-02-22 15:31:26 【问题描述】:

我最近开始在工作中使用 PostgreSQL,并且正在尝试优化查询以根据用户的 IP 地址对用户进行地理定位。我不完全确定如何读取解释分析的输出。自上次更新以来,所有表都已被清理,所以我知道这不是导致缓慢的原因。

我有以下表格:

session_ipaddress: 存储访问者的 IP 地址,大约有 250,000 行。相关列和索引:

session_id VARCHAR PRIMARY KEY,
ip_address INET,
ip_int BIGINT

BTREE INDEX on ip_int

ipblocks_201601: MaxMind GeoLite2 City Blocks 数据库从http://dev.maxmind.com/geoip/geoip2/geolite2/ 获得,另外两个列min_ipmax_ip 一起保存了CIDR 块中的IP 地址范围。相关的列和索引是:

network CIDR PRIMARY KEY,
geoname_id INTEGER,
min_ip BIGINT,
max_ip BIGINT

BTREE INDEX ON geoname_id
BTREE INDEX ON min_ip
BTREE INDEX ON max_ip

ipgeolookup_201601:en 语言环境的 GeoLite2 位置数据库。相关列和索引:

geoname_id INTEGER PRIMARY KEY,
country_name VARCHAR,
subdivision_1_name VARCHAR,
city_name VARCHAR

BTREE INDEX ON country_name
BTREE INDEX ON subdivision_1_name
BTREE INDEX ON city_name

这是我正在运行的查询,大约需要 20 秒才能完成。

SELECT
  geo.country_name
, geo.subdivision_1_name region_name
, geo.city_name
, COUNT(s.session_id) location_unresolved
FROM session_ipaddress s
JOIN ipblocks_201601 ip ON ip.min_ip <= s.ip_int AND ip.max_ip >= s.ip_int
JOIN ipgeolookup_201601 geo ON geo.geoname_id = ip.geoname_id
WHERE geo.country_name = 'United States' OR geo.country_name = 'Canada'
GROUP BY 1, 2, 3;

总运行时间:22192.814 毫秒,这是EXPLAIN ANALYZE 的输出:http://explain.depesz.com/s/DNcV

【问题讨论】:

您确定您的explain analyze 与此查询匹配吗?因为有一个按contry_name 排序,而您的查询没有这种排序。 是的,我确信解释分析是针对这个查询的。我不确定它为什么需要排序,我认为它与聚合有关。它还对city_namesubdivision_1_name 字段进行排序。 为什么是最小/最大 ip?你就不能network &gt;&gt; ip_address吗? network &gt;&gt; ip_address 甚至更慢且不使用索引。不知道为什么,但是将范围提​​取到单独的列中并转换为整数,将速度提升到当前级别。 【参考方案1】:

你应该尝试添加复合索引。

ipblocks_201601 包含 (geoname_id, min_ip, max_ip)

另一个ipgeolookup_201601 包括(country_name, geoname_id)

由 OP 编辑​​:

最大的改进来源是将 work_mem 从默认的 1MB 增加到 4MB。数据库位于具有 2GB 内存的机器上。 执行时间从 20 秒缩短到 5 秒

添加复合索引进一步降低了执行时间。

【讨论】:

最大的改进来自于将work_mem 从 1MB 增加到 4MB(查询时间 ~ 5 秒)。之后,(country_name, geoname_id)(min_ip, max_ip) 上的复合索引将查询时间减少到约 4 秒。有趣的是,我尝试在(geoname_id, min_ip, max_ip) 上使用复合索引进行查询,但并没有提高性能,但该索引的创建时间比(min_ip, max_ip) 的创建时间要长得多 好吧,我选择了work_mem,因为在说明中您可以看到排序是在磁盘而不是内存中执行的。问题是work_mem 是每个操作,所以如果你有很多连接打开,你可以超载服务器。也许您应该阅读此dba.stackexchange.com/questions/27893/… 谢谢!这就是我实现的:客户端在运行查询之前执行set local work_mem='4MB';,然后立即提交。因此,其他连接将获得默认的1MB work_mem 你能分享一下新的解释吗?

以上是关于IP地理位置查询太慢的主要内容,如果未能解决你的问题,请参考以下文章

python查询公网IP地址、IP地理位置

Python脚本查询IP的地理位置

从 bigquery 开放数据库查询 IP 地理位置数据:geolite2

怎样根据ip察地理位置??

php获取了ip地址,用php怎么获取ip的地理位置?请大虾赐教!

如何利用 IP 归属地查询 API 精准锁定用户位置