我最近开始在工作中使用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_ip
和max_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 ms &这是 EXPLAIN ANALYZE
的输出:http://explain.depesz.com/s/DNcV
您应该尝试添加复合索引。
一个供ipblocks_201601
包含(geoname_id, min_ip, max_ip)
另一个供ipgeolookup_201601
包括(country_name, geoname_id)
由OP编辑:
最大的改进来源是将work_mem从默认的 1MB 增加到 4MB。数据库位于具有 2GB 内存的计算机上。
执行力从 20 秒下降到 5 秒
添加复合索引进一步将执行时间缩短了一秒。