在 Postgres DB 中,我需要过滤表 A 中的数十万行,方法是仅包含行中 IP 地址列(inet 类型)与数千个 IP 地址块(输入 cidr) 在另一个表 B 中。我已经在第一个表中的 inet 地址和第二个表中的 cidr 范围上尝试了各种索引,但无论我做什么,规划器都会执行嵌套顺序扫描,应用 << operator to every pair of IP addresses and prefixes.
有没有办法通过索引或其他巧妙的技巧来加快速度? (我可以诉诸外部过程脚本,但我想知道它在 Postgres 中是否可行。)
谢谢!
这是一个老问题,但在 Google 结果中很突出,所以在这里发布我的 2 美分:
使用 Postgres 9.4 及更高版本,您可以对 inet 和 cidr 使用 GIST 索引:https://www.postgresql.org/docs/current/gist.html
例如以下查询将使用 gist 索引(假设来自 MaxMind 免费数据集的表):
create index on geolite2_city_ipv4_block using gist (network inet_ops);
select * from geolite2_city_ipv4_block where network >>= '8.8.8.8';
你看过ip4r吗? http://pgfoundry.org/projects/ip4r。 IIRC,INET 相关的查找真的很快。
案件结案。为了让事情变得更快,请执行以下操作:
使用 http://pgfoundry.org/projects/ip4r 提供的 ip4r 类型,如用户 bma 所指出的。此类型支持索引,而 Postgres(直至 Postgres 9.3)本机不支持索引。
不要直接使用 ip4r 类型,而是按照用户 caskey 的建议和 ip4r 文档中提到的将其扩展为下限值和上限值:https://github.com/petere/ip4r-cvs/blob/master/README .ip4r#L187
鉴于上述情况,如果您对所有比较地址使用 ip4 类型(假设您正在处理 v4 地址),那么规划器将利用这些列上的索引。
谢谢大家的帮助!
已经部署了确保 CIDR 不重叠的规则,我只是使用了索引
btree tablename(network(addr))
给出
target
作为输入检查,如下所示:
SELECT target <<= addr FROM tablename WHERE network(addr) <= target ORDER BY network(addr) DESC LIMIT 1;
成功时返回 true,失败时返回 false 或不返回任何内容。