有没有办法更有效地生成〜百万个MAC地址?
这是我正在做的事情,但是需要大约10分钟来生成一百万个MAC地址并将它们插入我的表中:
DECLARE @StartRange BINARY(6)
DECLARE @EndRange BINARY(6)
SET @StartRange = 0x0036D1F00000
SET @EndRange = 0x0036D1FFFFFF
--select convert(bigint,+ @EndRange) - convert(bigint,+ @StartRange) = 1048575
WHILE(convert(bigint, (SELECT IDENT_CURRENT('Mac_Address'))) < (convert(bigint, @EndRange) - convert(bigint, @StartRange)))
BEGIN
insert into Mac_Address (MacAddress)
select convert(BINARY(6),(convert(bigint, (SELECT IDENT_CURRENT('Mac_Address'))) + convert(bigint, @StartRange)))
END
这是我在网上找到的代码,它会在几秒钟后执行。但是它会在系统表中生成MAC地址:
DECLARE @StartRange BINARY(8)
DECLARE @EndRange BINARY(8)
SET @StartRange = 0x00000004A500114B
SET @EndRange = 0x00000004A50F11FF
--select convert(integer,+ @EndRange) - convert(integer,+ @StartRange) = 983220
select convert(BINARY(8),RW + convert(integer, @StartRange))
from
(select row_number() over(order by a.id) As RW from syscolumns,syscolumns a,syscolumns b ,syscolumns c) b --I do not understand this line very well.
where RW between 1 and (convert(integer, @EndRange) - convert(integer, @StartRange))
答案 0 :(得分:4)
如你所说,它不是“在系统表中生成MAC地址”。它只是使用syscolumns
表作为获取大量行的手段。您可以知道这一点,因为所有系统表都在FROM
子句中。要插入表格,至少需要INSERT
或SELECT ... INTO
。
它快速的原因是因为SQL Server针对“基于行”的操作进行了优化。在引擎内部,当然它必须遍历每一行,但它经过了大量优化。当您将T-SQL视为过程语言并一次循环一个项时,它不能使用这些优化,并且必须在完全不同的执行上下文下一次执行一个语句。
syscolumns
表本身毫无意义。它有价值,因为它保证有很多行。它可以是任何包含许多行的表 - FROM
子句中的表只是交叉连接在一起以获取其笛卡尔积(意味着很多行),以便Row_Number()
函数具有某些东西使用来创建一个数字从1到1,000,000的行集。
如果你愿意,你可以使用这样的方法,它根本不会打到任何“真正的”表,它应该表现得同样快或更快。它所做的只是取最初的SELECT 1 UNION ALL SELECT 1
并通过重复CROSS JOIN
将其转换为4.3 bilion行(但使用FROM Table1, Table2
的旧式语法,与{{1}相同但是更短)。
我在SQL 2008中测试了以下内容,它运行良好。我的SQL Server需要 3秒(SQL Fiddle此时错误地抛出错误,我已通过电子邮件发送给管理员)。
FROM Table1 CROSS JOIN Table2
但是,我并不是100%确定这可以在SQL Server 2012的Express版本中使用。使用DECLARE
@StartRange bigint = 0x0004A500114B,
@EndRange bigint = 0x0004A50F11FF;
WITH -- make sure you terminate your prior statement by putting ; after it
L0 AS (SELECT 1 N UNION ALL SELECT 1),
L1 AS (SELECT 1 N FROM L0, L0 B),
L2 AS (SELECT 1 N FROM L1, L1 B),
L3 AS (SELECT 1 N FROM L2, L2 B),
L4 AS (SELECT 1 N FROM L3, L3 B),
L5 AS (SELECT 1 N FROM L4, L4 B),
Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) N FROM L5)
INSERT Mac_Address (MacAddress)
SELECT Convert(binary(6), N + @StartRange - 1)
FROM Nums
WHERE N <= @EndRange - @StartRange + 1
版本实际上没有任何问题,您只需要添加syscolumns
语句并纠正一些问题(包括INSERT
而不是int
和bigint
而不是binary(8)
)。请注意,您可以通过在每个binary(6)
表之后添加WITH (NOLOCK)
(或在查询之前使用syscolumns
并在之后使用SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
)来提高性能。此查询也执行得很好(我的服务器上2秒)。
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
答案 1 :(得分:1)
第二个片段根本没有插入任何内容。它只使用syscolumns表(与自身交叉连接)行号来生成整数。
您可以使用任何其他表格(假设您有足够的行数或加入足够的时间来生成它)
答案 2 :(得分:1)
它实际上并没有使用syscolumns。它只是将它连接在一起,以创建一个包含足够范围的行的表。如果您对此感到不舒服,可以执行以下操作:
with digits as (select 0 as dig union all
select 1 union all
select 2 union all
select 3 union all
select 4 union all
select 5 union all
select 6 union all
select 7 union all
select 8 union all
select 9
),
nums as (select dig1 + 10*dig2+100*dig3+1000*dig4+10000*dig5+100000*dig6 as num
from dig dig1 cross join dig dig2 cross join
dig dig3 cross join dig dig4 cross join
dig dig5 cross join dig dig6
)
select convert(BINARY(8), num + convert(integer, @StartRange))
from nums
where num + 1 between 1 and (convert(integer, @EndRange) - convert(integer, @StartRange))
答案 3 :(得分:1)
以下内容很简单,大约在一分钟内在线SqlFiddle上运行:
DECLARE @StartRange bigint;
DECLARE @EndRange bigint;
SET @StartRange = 0x0036D1F00000;
SET @EndRange = 0x0036D1FFFFFF;
WITH cteMacAddress AS (
SELECT @StartRange MacAddress
UNION ALL
SELECT MacAddress+1 FROM cteMacAddress
WHERE MacAddress <= @EndRange
)
INSERT Mac_Address
SELECT CAST(MacAddress AS BINARY(6))
FROM cteMacAddress
OPTION (MAXRECURSION 0);
SELECT COUNT(*) GeneratedAddressCount
FROM Mac_Address;