【问题标题】:Find list/ranges of available IP addresses within subnet efficiently有效地查找子网内可用 IP 地址的列表/范围
【发布时间】:2020-01-03 04:48:06
【问题描述】:

我正在尝试确定下一个可用的 IP 地址被赋予一个子网(基本上是一个起始 IPv4 地址和一个结束 IPv4 地址)和一个包含已分配 IPv4 地址的 addresses 表。

表格的简化架构:

CREATE TABLE addresses (
    address INET NOT NULL,
    -- OTHER INFORMATION ASSOCIATED WITH IP ADDRESSES --
);

当前实现在子网内生成所有可能的 IP 地址,并返回那些不在 addresses 表中的 IP 地址。

例如,给定一个子网,其起始 IP 为“192.0.0.0”,结束 IP 为“192.0.0.255”,查询将如下所示:

SELECT * 
FROM (
  SELECT i + '0.0.0.0' :: inet as generated_address
  from generate_series('192.0.0.0' :: inet - '0.0.0.0' :: inet,
                       '192.0.0.255' :: inet - '0.0.0.0' :: inet) as i) as iprange
                       WHERE generated_address NOT IN (SELECT address FROM addresses);

这可以正常工作,但问题是对于 /12 和更低的子网掩码它开始变慢,并且对于 /8 的子网掩码根本没有完成。

我正在尝试确定查找下一个可用 IP 地址的替代方法。
此外,如果我可以返回可用 IP 地址列表或范围列表(表示可用 IP 地址与不可用 IP 地址之间的差距),那将是理想的。

post 上似乎有一些与此问题相关的好答案,但我发现很难理解该帖子中的答案并将它们翻译成我在 postgres 中的情况(因为我对它相当陌生)。

数据

我不完全确定数据会是什么样子,但地址表填充方式的 3 种情况如下:

  1. 稀疏(分配的 IP 地址很少)
  2. 不稳定(子网的一半已填满,但之间有很多间隙)
  3. 密集(占用大多数 IP 地址)

最坏的情况可能是情况 3,因为它需要查看所有记录。

我提供了一个简单的DB Fiddle 来演示该场景。

【问题讨论】:

  • 您是否考虑过保留一个包含免费 IP 范围列表的表格?这可能会变得非常碎片化,但如果您不分配最低可用地址,但可能不会那么多,而是分配最小可用范围的第一个地址。您可以索引大小。
  • 这是我可以考虑的一种可能的替代解决方案,但现在我更喜欢不包括创建另一个表的解决方案。
  • 我的意思是把这张桌子作为唯一的桌子。无论如何,如果您的解决方案对您来说足够高效,那很好。
  • 好吧,在问题中我简化了架构,但我将编辑问题以包括它们与addresses 表的每一行相关联的信息这一事实。为混乱道歉

标签: sql postgresql ip subnet


【解决方案1】:

我设法想出了这样的事情:

WITH gaps (start_ip, end_ip) as 
(
   SELECT
      address + 1 AS start_ip,
      next_address - 1 AS end_ip 
   FROM
      (
         SELECT
            address,
            LEAD(address) OVER (
         ORDER BY
            address) AS next_address 
         FROM
            addresses 
         where
            and address >= '192.0.0.0' :: INET -- Start Address
            and address <= '192.0.255.255' :: INET -- End Address
      )
      AS gaps 
   WHERE
      gaps.address + 1 <> gaps.next_address
)
SELECT
   generate_series(start_ip - '0.0.0.0' :: INET, end_ip - '0.0.0.0' :: INET) + '0.0.0.0'::INET as address 
FROM
   gaps

同样,大部分内容本质上是此post 中答案的翻译,但我认为它仍然可以帮助其他人在这里获得它。

一般的想法是在addresses 表(此处已分配地址)中寻找“空白”,这意味着介于两者之间的所有内容都是“免费的”。如果 LEAD 中的next_address 仅比当前的address 大 1,则表示下一个地址已被占用,没有间隙。 这是DBFiddle

我仍在寻找更有效的解决方案,尤其是在地址表非常密集或满的情况下,最坏的情况是子网中只有最后一个 IP 地址是空闲的......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-23
    • 1970-01-01
    • 2013-08-22
    • 2020-01-10
    • 2021-01-24
    • 2016-02-04
    • 2020-05-23
    • 2023-03-28
    相关资源
    最近更新 更多