问题陈述:
given a range
x -> y
of unsigned integers
wherex
andy
are both in the range0 -> 2
n
andn
is0 -> 32
(or 64 in alternate cases)
find the minimum available value
not equal tox
ory
that is not in an existing set
where existing sets are arbitrary subsets ofx -> y
我正在对数据库中的 IPv4 和 IPv6 子网进行建模。每个子网由其起始地址和结束地址定义(我通过业务规则确保范围的完整性)。因为 IPv6 太大,无法存储在
bigint
数据类型我们将 IP 地址存储为 binary(4)
或 binary(16)
.关联的数据存储在
subnet
, dhcp_range
和 ip_address
表:子网范围由开始和结束 IP 地址定义并存储在
subnet
中。 table 。子网范围的大小始终为 2n(根据 CIDR/网络掩码的定义)。 一个子网有
0..*
IP地址存储在ip_address
table 。 IP 地址必须介于起始地址和结束地址之间,但不等于其关联子网定义的范围。 一个子网有
0..*
DHCP 范围存储在 dhcp_range
中 table 。类似于子网,每个 DHCP 范围都定义了一个开始地址和结束地址。 DHCP 范围受相关子网范围的限制。 DHCP 范围彼此不重叠。 我要确定的是子网的下一个可用 IP:
我正在寻找一种可以找到最小可用地址或所有可用地址的解决方案。
我最初的想法是生成由子网范围绑定(bind)的可能地址(数字)的范围,然后根据使用的集合删除地址:
declare @subnet_sk int = 42
;with
address_range as (
select cast(ipv4_begin as bigint) as available_address
,cast(ipv4_end as bigint) as end_address, subnet_sk
from subnet s
where subnet_sk = @subnet_sk
union all
select available_address + 1, end_address, subnet_sk
from address_range
where available_address + 1 <= end_address
),
assigned_addresses as (
select ip.[address]
,subnet_sk
from ip_address ip
where ip.subnet_sk = @subnet_sk
and ip.address_family = 'InterNetwork'),
dhcp_ranges as (
select dhcp.begin_address
,dhcp.end_address
,subnet_sk
from dhcp_range dhcp
where dhcp.subnet_sk = @subnet_sk
and dhcp.address_family = 'InterNetwork')
select distinct ar.available_address
from address_range ar
join dhcp_ranges dhcp
on ar.available_address
not between dhcp.begin_address
and dhcp.end_address
left join assigned_addresses aa
on ar.available_address = aa.[address]
join subnet s
on ar.available_address != s.ipv4_begin
and ar.available_address != s.ipv4_end
where aa.[address] is null
and s.subnet_sk = @subnet_sk
order by available_address
option (MAXRECURSION 32767)
上述查询使用递归 CTE,不适用于所有数据排列。递归 CTE 很麻烦,因为它的最大大小限制为 32,767(远小于潜在的范围大小),并且很可能非常慢。我可能可以克服递归 CTE 的问题,但查询在以下情况下失败:
应返回子网范围
为了帮助解决问题,我创建了一个 SQL Fiddle具有三个子网;每个都有不同的特征:切碎、空的或大部分是连续的。上面的查询和 fiddle 中的设置都适用于大部分连续的子网,但不适用于其他子网。还有一个GitHub Gist of the schema and example data .
我已经努力用递归和堆叠 CTE 生成数字序列,但如上所述,恐怕它们的性能会很差,并且在递归 CTE 的情况下会人为地限制。 Aaron Bertrand在他的系列中详细介绍了 CTE 的一些替代方案 Generate a set or sequence without loops .遗憾的是,数据集对于数字表来说太大了,因为仅为 IPv4 地址空间创建一个需要 32 GB 的磁盘空间(SQL Server 存储
bigint
values in 8 bytes)。我更喜欢动态生成序列,但还没有想出一个好的方法。或者,我试图通过查看我知道的使用地址来为我的查询设定种子:
declare @subnet_sk int = 1
select unassigned_range.*
from (select cast(l.address as bigint) + 1 as start
,min(cast(fr.address as bigint)) - 1 as stop
from ip_address as l
left join ip_address as r on l.address = r.address - 1
left join ip_address as fr on l.address < fr.address
where r.address is null and fr.address is not null
and l.subnet_sk = @subnet_sk
group by l.address, r.address) as unassigned_range
join dhcp_range dhcp
on unassigned_range.start
not between cast(dhcp.begin_address as bigint)
and cast(dhcp.end_address as bigint)
and unassigned_range.stop
not between cast(dhcp.begin_address as bigint)
and cast(dhcp.end_address as bigint)
where dhcp.subnet_sk = @subnet_sk
遗憾的是,当
ip_address
中没有任何内容时,上述查询不起作用。或 dhcp_range
表。更糟糕的是,它不知道子网范围的边界 dhcp_range
接近子网范围的上限将人为地限制返回的内容,因为查询无法从边缘的空白空间返回行。表现也不算突出。使用 SQL 或 TSQL 如何确定受其他范围限制的任意整数范围内的下一个最小可用整数值?
最佳答案
在这种情况下不需要递归,因为我们有 LEAD
功能。
我会从“差距”和“孤岛”的角度来思考问题。
我将首先关注 IPv4,因为用它们做算术更容易,但 IPv6 的想法是相同的,最后我将展示一个通用的解决方案。
首先,我们有一系列可能的 IP:从 0x00000000
至 0xFFFFFFFF
.
在此范围内,存在由 dhcp_range
中的范围(含)定义的“孤岛”。 :dhcp_range.begin_address, dhcp_range.end_address
.您可以将分配的 IP 地址列表视为另一组孤岛,每个孤岛都有一个元素:ip_address.address, ip_address.address
.最后,子网本身是两个孤岛:0x00000000, subnet.ipv4_begin
和 subnet.ipv4_end, 0xFFFFFFFF
.
我们知道这些岛屿做不是 重叠,这让我们的生活更轻松。岛屿可以完全相邻。例如,当您有几个连续分配的 IP 地址时,它们之间的差距为零。
在所有这些岛中,我们需要找到第一个间隙,它至少有一个元素,即非零间隙,即下一个岛在前一个岛结束后的某个距离处开始。
因此,我们将使用 UNION
将所有岛屿放在一起( CTE_Islands
) 然后按照 end_address
的顺序遍历所有这些(或 begin_address
,使用具有索引的字段)并使用 LEAD
向前看并获得下一个岛屿的起始地址。最后我们将有一个表格,其中每一行都有 end_address
当前岛屿和 begin_address
下一个岛屿 ( CTE_Diff
)。如果它们之间的差异大于一,则表示“间隙”足够宽,我们将返回 end_address
当前岛屿的加1。
给定子网的第一个可用 IP 地址
DECLARE @ParamSubnet_sk int = 1;
WITH
CTE_Islands
AS
(
SELECT CAST(begin_address AS bigint) AS begin_address, CAST(end_address AS bigint) AS end_address
FROM dhcp_range
WHERE subnet_sk = @ParamSubnet_sk
UNION ALL
SELECT CAST(address AS bigint) AS begin_address, CAST(address AS bigint) AS end_address
FROM ip_address
WHERE subnet_sk = @ParamSubnet_sk
UNION ALL
SELECT CAST(0x00000000 AS bigint) AS begin_address, CAST(ipv4_begin AS bigint) AS end_address
FROM subnet
WHERE subnet_sk = @ParamSubnet_sk
UNION ALL
SELECT CAST(ipv4_end AS bigint) AS begin_address, CAST(0xFFFFFFFF AS bigint) AS end_address
FROM subnet
WHERE subnet_sk = @ParamSubnet_sk
)
,CTE_Diff
AS
(
SELECT
begin_address
, end_address
--, LEAD(begin_address) OVER(ORDER BY end_address) AS BeginNextIsland
, LEAD(begin_address) OVER(ORDER BY end_address) - end_address AS Diff
FROM CTE_Islands
)
SELECT TOP(1)
CAST(end_address + 1 AS varbinary(4)) AS NextAvailableIPAddress
FROM CTE_Diff
WHERE Diff > 1
ORDER BY end_address;
如果至少有一个 IP 地址可用,则结果集将包含一行;如果没有可用的 IP 地址,则结果集将根本不包含行。
For parameter 1 result is `0xAC101129`.
For parameter 2 result is `0xC0A81B1F`.
For parameter 3 result is `0xC0A8160C`.
这是指向 SQLFiddle 的链接.它不适用于参数,所以我硬编码
1
那里。在 UNION 中将其更改为其他子网 ID(2 或 3)以尝试其他子网。此外,它没有在 varbinary
中显示结果正确,所以我将其保留为 bigint。使用,例如,windows 计算器将其转换为十六进制以验证结果。如果您不通过
TOP(1)
将结果限制在第一个间隔内,您将获得所有可用 IP 范围(间隙)的列表。给定子网的所有可用 IP 地址范围列表
DECLARE @ParamSubnet_sk int = 1;
WITH
CTE_Islands
AS
(
SELECT CAST(begin_address AS bigint) AS begin_address, CAST(end_address AS bigint) AS end_address
FROM dhcp_range
WHERE subnet_sk = @ParamSubnet_sk
UNION ALL
SELECT CAST(address AS bigint) AS begin_address, CAST(address AS bigint) AS end_address
FROM ip_address
WHERE subnet_sk = @ParamSubnet_sk
UNION ALL
SELECT CAST(0x00000000 AS bigint) AS begin_address, CAST(ipv4_begin AS bigint) AS end_address
FROM subnet
WHERE subnet_sk = @ParamSubnet_sk
UNION ALL
SELECT CAST(ipv4_end AS bigint) AS begin_address, CAST(0xFFFFFFFF AS bigint) AS end_address
FROM subnet
WHERE subnet_sk = @ParamSubnet_sk
)
,CTE_Diff
AS
(
SELECT
begin_address
, end_address
, LEAD(begin_address) OVER(ORDER BY end_address) AS BeginNextIsland
, LEAD(begin_address) OVER(ORDER BY end_address) - end_address AS Diff
FROM CTE_Islands
)
SELECT
CAST(end_address + 1 AS varbinary(4)) AS begin_range_AvailableIPAddress
,CAST(BeginNextIsland - 1 AS varbinary(4)) AS end_range_AvailableIPAddress
FROM CTE_Diff
WHERE Diff > 1
ORDER BY end_address;
结果。 SQL Fiddle结果为简单的 bigint,不是十六进制的,并且带有硬编码的参数 ID。
Result set for ID = 1
begin_range_AvailableIPAddress end_range_AvailableIPAddress
0xAC101129 0xAC10112E
Result set for ID = 2
begin_range_AvailableIPAddress end_range_AvailableIPAddress
0xC0A81B1F 0xC0A81B1F
0xC0A81B22 0xC0A81B28
0xC0A81BFA 0xC0A81BFE
Result set for ID = 3
begin_range_AvailableIPAddress end_range_AvailableIPAddress
0xC0A8160C 0xC0A8160C
0xC0A816FE 0xC0A816FE
每个子网的第一个可用 IP 地址
扩展查询并返回所有子网的第一个可用 IP 地址很容易,而不是指定一个特定的子网。使用
CROSS APPLY
获取每个子网的岛屿列表,然后添加 PARTITION BY subnet_sk
进LEAD
功能。WITH
CTE_Islands
AS
(
SELECT
subnet_sk
, begin_address
, end_address
FROM
subnet AS Main
CROSS APPLY
(
SELECT CAST(begin_address AS bigint) AS begin_address, CAST(end_address AS bigint) AS end_address
FROM dhcp_range
WHERE dhcp_range.subnet_sk = Main.subnet_sk
UNION ALL
SELECT CAST(address AS bigint) AS begin_address, CAST(address AS bigint) AS end_address
FROM ip_address
WHERE ip_address.subnet_sk = Main.subnet_sk
UNION ALL
SELECT CAST(0x00000000 AS bigint) AS begin_address, CAST(ipv4_begin AS bigint) AS end_address
FROM subnet
WHERE subnet.subnet_sk = Main.subnet_sk
UNION ALL
SELECT CAST(ipv4_end AS bigint) AS begin_address, CAST(0xFFFFFFFF AS bigint) AS end_address
FROM subnet
WHERE subnet.subnet_sk = Main.subnet_sk
) AS CA
)
,CTE_Diff
AS
(
SELECT
subnet_sk
, begin_address
, end_address
, LEAD(begin_address) OVER(PARTITION BY subnet_sk ORDER BY end_address) - end_address AS Diff
FROM CTE_Islands
)
SELECT
subnet_sk
, CAST(MIN(end_address) + 1 as varbinary(4)) AS NextAvailableIPAddress
FROM CTE_Diff
WHERE Diff > 1
GROUP BY subnet_sk
结果集
subnet_sk NextAvailableIPAddress
1 0xAC101129
2 0xC0A81B1F
3 0xC0A8160C
这是SQLFiddle .我不得不删除转换为
varbinary
在 SQL Fiddle 中,因为它显示的结果不正确。IPv4 和 IPv6 的通用解决方案
所有子网的所有可用 IP 地址范围
SQL Fiddle with sample IPv4 and IPv6 data, functions and final query
您的 IPv6 示例数据不太正确 - 子网结束
0xFC00000000000000FFFFFFFFFFFFFFFF
小于您的 dhcp 范围,所以我将其更改为 0xFC0001066800000000000000FFFFFFFF
.此外,您在同一子网中同时拥有 IPv4 和 IPv6,处理起来很麻烦。为了这个例子,我稍微改变了你的模式 - 而不是显式 ipv4_begin / end
和 ipv6_begin / end
在 subnet
我刚做的 ip_begin / end
如 varbinary(16)
(与您的其他表相同)。我也删除了 address_family
,否则它对于 SQL Fiddle 来说太大了。算术函数
为了使其适用于 IPv6,我们需要弄清楚如何添加/减去
1
往/返 binary(16)
.我会为它制作 CLR 功能。如果不允许启用 CLR,则可以通过标准 T-SQL 进行。我创建了两个返回表而不是标量的函数,因为这样它们可以被优化器内联。我想做一个通用的解决方案,所以函数会接受 varbinary(16)
并适用于 IPv4 和 IPv6。这是用于递增
varbinary(16)
的 T-SQL 函数由一个。如果参数不是 16 字节长,我假设它是 IPv4 并简单地将其转换为 bigint
添加 1
然后回到 binary
.否则,我 split binary(16)
分成两部分,每部分 8 个字节,然后将它们转换为 bigint
. bigint
是有符号的,但我们需要无符号增量,所以我们需要检查一些情况。else
部分是最常见的 - 我们只是将低部分加一并将结果附加到原始高部分。如果低部分是
0xFFFFFFFFFFFFFFFF
,然后我们将低部分设置为 0x0000000000000000
并结转标志,即将高部分加一。如果低部分是
0x7FFFFFFFFFFFFFFF
,然后我们将低部分设置为 0x8000000000000000
明确地,因为试图增加这个 bigint
value 会导致溢出。如果整数是
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
我们将结果设置为 0x00000000000000000000000000000000
.减一的功能类似。
CREATE FUNCTION [dbo].[BinaryInc](@src varbinary(16))
RETURNS TABLE AS
RETURN
SELECT
CASE WHEN DATALENGTH(@src) = 16
THEN
-- Increment IPv6 by splitting it into two bigints 8 bytes each and then concatenating them
CASE
WHEN @src = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
THEN 0x00000000000000000000000000000000
WHEN SUBSTRING(@src, 9, 8) = 0x7FFFFFFFFFFFFFFF
THEN SUBSTRING(@src, 1, 8) + 0x8000000000000000
WHEN SUBSTRING(@src, 9, 8) = 0xFFFFFFFFFFFFFFFF
THEN CAST(CAST(SUBSTRING(@src, 1, 8) AS bigint) + 1 AS binary(8)) + 0x0000000000000000
ELSE SUBSTRING(@src, 1, 8) + CAST(CAST(SUBSTRING(@src, 9, 8) AS bigint) + 1 AS binary(8))
END
ELSE
-- Increment IPv4 by converting it into 8 byte bigint and then back into 4 bytes binary
CAST(CAST(CAST(@src AS bigint) + 1 AS binary(4)) AS varbinary(16))
END AS Result
;
GO
CREATE FUNCTION [dbo].[BinaryDec](@src varbinary(16))
RETURNS TABLE AS
RETURN
SELECT
CASE WHEN DATALENGTH(@src) = 16
THEN
-- Decrement IPv6 by splitting it into two bigints 8 bytes each and then concatenating them
CASE
WHEN @src = 0x00000000000000000000000000000000
THEN 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
WHEN SUBSTRING(@src, 9, 8) = 0x8000000000000000
THEN SUBSTRING(@src, 1, 8) + 0x7FFFFFFFFFFFFFFF
WHEN SUBSTRING(@src, 9, 8) = 0x0000000000000000
THEN CAST(CAST(SUBSTRING(@src, 1, 8) AS bigint) - 1 AS binary(8)) + 0xFFFFFFFFFFFFFFFF
ELSE SUBSTRING(@src, 1, 8) + CAST(CAST(SUBSTRING(@src, 9, 8) AS bigint) - 1 AS binary(8))
END
ELSE
-- Decrement IPv4 by converting it into 8 byte bigint and then back into 4 bytes binary
CAST(CAST(CAST(@src AS bigint) - 1 AS binary(4)) AS varbinary(16))
END AS Result
;
GO
所有子网的所有可用 IP 地址范围
WITH
CTE_Islands
AS
(
SELECT subnet_sk, begin_address, end_address
FROM dhcp_range
UNION ALL
SELECT subnet_sk, address AS begin_address, address AS end_address
FROM ip_address
UNION ALL
SELECT subnet_sk, SUBSTRING(0x00000000000000000000000000000000, 1, DATALENGTH(ip_begin)) AS begin_address, ip_begin AS end_address
FROM subnet
UNION ALL
SELECT subnet_sk, ip_end AS begin_address, SUBSTRING(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, 1, DATALENGTH(ip_end)) AS end_address
FROM subnet
)
,CTE_Gaps
AS
(
SELECT
subnet_sk
,end_address AS EndThisIsland
,LEAD(begin_address) OVER(PARTITION BY subnet_sk ORDER BY end_address) AS BeginNextIsland
FROM CTE_Islands
)
,CTE_GapsIncDec
AS
(
SELECT
subnet_sk
,EndThisIsland
,EndThisIslandInc
,BeginNextIslandDec
,BeginNextIsland
FROM CTE_Gaps
CROSS APPLY
(
SELECT bi.Result AS EndThisIslandInc
FROM dbo.BinaryInc(EndThisIsland) AS bi
) AS CA_Inc
CROSS APPLY
(
SELECT bd.Result AS BeginNextIslandDec
FROM dbo.BinaryDec(BeginNextIsland) AS bd
) AS CA_Dec
)
SELECT
subnet_sk
,EndThisIslandInc AS begin_range_AvailableIPAddress
,BeginNextIslandDec AS end_range_AvailableIPAddress
FROM CTE_GapsIncDec
WHERE CTE_GapsIncDec.EndThisIslandInc <> BeginNextIsland
ORDER BY subnet_sk, EndThisIsland;
结果集
subnet_sk begin_range_AvailableIPAddress end_range_AvailableIPAddress
1 0xAC101129 0xAC10112E
2 0xC0A81B1F 0xC0A81B1F
2 0xC0A81B22 0xC0A81B28
2 0xC0A81BFA 0xC0A81BFE
3 0xC0A8160C 0xC0A8160C
3 0xC0A816FE 0xC0A816FE
4 0xFC000000000000000000000000000001 0xFC0000000000000000000000000000FF
4 0xFC000000000000000000000000000101 0xFC0000000000000000000000000001FF
4 0xFC000000000000000000000000000201 0xFC0000000000000000000000000002FF
4 0xFC000000000000000000000000000301 0xFC0000000000000000000000000003FF
4 0xFC000000000000000000000000000401 0xFC0000000000000000000000000004FF
4 0xFC000000000000000000000000000501 0xFC0000000000000000000000000005FF
4 0xFC000000000000000000000000000601 0xFC0000000000000000000000000006FF
4 0xFC000000000000000000000000000701 0xFC0000000000000000000000000007FF
4 0xFC000000000000000000000000000801 0xFC0000000000000000000000000008FF
4 0xFC000000000000000000000000000901 0xFC00000000000000BFFFFFFFFFFFFFFD
4 0xFC00000000000000BFFFFFFFFFFFFFFF 0xFC00000000000000CFFFFFFFFFFFFFFD
4 0xFC00000000000000CFFFFFFFFFFFFFFF 0xFC00000000000000FBFFFFFFFFFFFFFD
4 0xFC00000000000000FBFFFFFFFFFFFFFF 0xFC00000000000000FCFFFFFFFFFFFFFD
4 0xFC00000000000000FCFFFFFFFFFFFFFF 0xFC00000000000000FFBFFFFFFFFFFFFD
4 0xFC00000000000000FFBFFFFFFFFFFFFF 0xFC00000000000000FFCFFFFFFFFFFFFD
4 0xFC00000000000000FFCFFFFFFFFFFFFF 0xFC00000000000000FFFBFFFFFFFFFFFD
4 0xFC00000000000000FFFBFFFFFFFFFFFF 0xFC00000000000000FFFCFFFFFFFFFFFD
4 0xFC00000000000000FFFCFFFFFFFFFFFF 0xFC00000000000000FFFFBFFFFFFFFFFD
4 0xFC00000000000000FFFFBFFFFFFFFFFF 0xFC00000000000000FFFFCFFFFFFFFFFD
4 0xFC00000000000000FFFFCFFFFFFFFFFF 0xFC00000000000000FFFFFBFFFFFFFFFD
4 0xFC00000000000000FFFFFBFFFFFFFFFF 0xFC00000000000000FFFFFCFFFFFFFFFD
4 0xFC00000000000000FFFFFCFFFFFFFFFF 0xFC00000000000000FFFFFFBFFFFFFFFD
4 0xFC00000000000000FFFFFFBFFFFFFFFF 0xFC00000000000000FFFFFFCFFFFFFFFD
4 0xFC00000000000000FFFFFFCFFFFFFFFF 0xFC00000000000000FFFFFFFBFFFFFFFD
4 0xFC00000000000000FFFFFFFBFFFFFFFF 0xFC00000000000000FFFFFFFCFFFFFFFD
4 0xFC00000000000000FFFFFFFCFFFFFFFF 0xFC00000000000000FFFFFFFFBFFFFFFD
4 0xFC00000000000000FFFFFFFFBFFFFFFF 0xFC00000000000000FFFFFFFFCFFFFFFD
4 0xFC00000000000000FFFFFFFFCFFFFFFF 0xFC00000000000000FFFFFFFFFBFFFFFD
4 0xFC00000000000000FFFFFFFFFBFFFFFF 0xFC00000000000000FFFFFFFFFCFFFFFD
4 0xFC00000000000000FFFFFFFFFCFFFFFF 0xFC00000000000000FFFFFFFFFFBFFFFD
4 0xFC00000000000000FFFFFFFFFFBFFFFF 0xFC00000000000000FFFFFFFFFFCFFFFD
4 0xFC00000000000000FFFFFFFFFFCFFFFF 0xFC00000000000000FFFFFFFFFFFBFFFD
4 0xFC00000000000000FFFFFFFFFFFBFFFF 0xFC00000000000000FFFFFFFFFFFCFFFD
4 0xFC00000000000000FFFFFFFFFFFCFFFF 0xFC00000000000000FFFFFFFFFFFFBFFD
4 0xFC00000000000000FFFFFFFFFFFFBFFF 0xFC00000000000000FFFFFFFFFFFFCFFD
4 0xFC00000000000000FFFFFFFFFFFFCFFF 0xFC00000000000000FFFFFFFFFFFFFBFD
4 0xFC00000000000000FFFFFFFFFFFFFBFF 0xFC00000000000000FFFFFFFFFFFFFCFD
4 0xFC00000000000000FFFFFFFFFFFFFCFF 0xFC00000000000000FFFFFFFFFFFFFFBD
4 0xFC00000000000000FFFFFFFFFFFFFFBF 0xFC00000000000000FFFFFFFFFFFFFFCD
4 0xFC00000000000000FFFFFFFFFFFFFFCF 0xFC0001065FFFFFFFFFFFFFFFFFFFFFFF
4 0xFC000106600000000000000100000000 0xFC00010666FFFFFFFFFFFFFFFFFFFFFF
4 0xFC000106670000000000000100000000 0xFC000106677FFFFFFFFFFFFFFFFFFFFF
4 0xFC000106678000000000000100000000 0xFC000106678FFFFFFFFFFFFFFFFFFFFF
4 0xFC000106679000000000000100000000 0xFC0001066800000000000000FFFFFFFE
执行计划
我很好奇这里建议的不同解决方案是如何工作的,所以我查看了他们的执行计划。请记住,这些计划适用于没有任何索引的小样本数据集。
我的 IPv4 和 IPv6 通用解决方案:
的类似解决方案dnoeth :
来自 的解决方案查不使用
LEAD
功能:关于sql - 使用sql在现有整数子集中不存在的范围内查找下一个可用整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28844504/