简体   繁体   English

postgresql cidr查找子块

[英]postgresql cidr find child blocks

I'm looking for a way to get direct children networks from cidr blocks stored in postgresql using the builtin cidr type. 我正在寻找一种使用内置cidr类型从存储在postgresql中的cidr块中获取直接子网络的方法。

Example database 示例数据库

CREATE TABLE nets (
    id serial primary key,
    net cidr
);
INSERT INTO nets (net) VALUES 
    ('10.1.0.0/16'),
    ('10.1.0.0/20'),
    ('10.1.1.0/24'),
    ('10.1.1.8/29'),
    ('10.1.1.32/28'),
    ('10.2.15.0/24'),
    ('10.2.15.64/27')

The desired query should fe 所需的查询应为

  • return 10.1.0.0/20 for searchkey 10.1.0.0/16 返回10.1.0.0/20作为搜索键10.1.0.0/16
  • 10.1.1.8/29 and 10.1.1.32/28 for searchkey 10.1.1.0/24 搜索键10.1.1.0/24的10.1.1.8/29和10.1.1.32/28

What I came up with is ( http://sqlfiddle.com/#!15/2b4b5/1 ): 我想出的是( http://sqlfiddle.com/#!15/2b4b5/1 ):

SELECT
  id,
  net
FROM 
  nets n
WHERE 
  net << '10.1.1.0/24' AND
  '10.1.1.0/24' IN (
    SELECT 
      net 
    FROM
      nets
    WHERE
      net >> n.net
    ORDER BY
      net DESC
    LIMIT 1
  )
ORDER BY 
  net

This gives the desired result, but it does not scale. 这样可以提供所需的结果,但无法缩放。 Even with only a few thousand entries in the database this gets terribly slow. 即使数据库中只有几千个条目,这也非常慢。

Is there another way to achieve this, without adding an explicit parent/child relationship to the database model? 是否有另一种方法可以实现此目标,而无需在数据库模型中添加显式的父/子关系?

Update : This is a variant, transformed from the Nested set model , it could be even faster (mainly on 9.4+ with the inet_ops GiST index): 更新 :这是从嵌套集模型转换而来的一个变体,它可能甚至更快(主要是在带有inet_ops GiST索引的inet_ops ):

SELECT c.id, c.net
FROM   nets c
WHERE  c.net << '10.1.1.0/24'
AND    NOT EXISTS(
  SELECT 1
  FROM   nets AS m
  WHERE  c.net << m.net AND m.net << '10.1.1.0/24'
);

Original answer : 原始答案

A simple EXCEPT should scale better with larger input-sets (it won't calculate a sub-plan for every child network): 一个简单的EXCEPT可以在较大的输入集下更好地扩展(它不会为每个子网络计算一个子计划):

(SELECT id, net
 FROM   nets
 WHERE  net << '10.1.1.0/24')
EXCEPT
(SELECT c.id, c.net
 FROM   nets p
 JOIN   nets c ON c.net << p.net
 WHERE  p.net << '10.1.1.0/24')
ORDER BY net;

Note : with smaller input-sets, the EXCEPT variant might be even slower than your query. 注意 :对于较小的输入集, EXCEPT变体甚至可能比查询慢。

But to maximize performance (both with this & with your query), you should use some index. 但是要最大程度地提高性能(与此查询一起使用),您应该使用一些索引。

If you have PostgreSQL 9.4+, you should use the new inet_ops GiST index: 如果您拥有PostgreSQL 9.4+,则应使用新的inet_ops GiST索引:

CREATE INDEX nets_inet_net_gist ON nets USING gist (inet(net) inet_ops);

Otherwise, you can use the network_ops btree index: 否则,您可以使用network_ops btree索引:

CREATE INDEX nets_inet_net_btree ON nets USING btree (inet(net) network_ops);

While inet_ops can directly use the << operator, network_ops will transform your expression to something like that: 尽管inet_ops可以直接使用<<运算符,但network_ops会将您的表达式转换为以下形式:

Index Cond: (((net)::inet > '10.1.1.0/24'::inet) AND ((net)::inet <= '10.1.1.255'::inet))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM