有没有办法更有效地生成〜百万个mac地址?

时间:2012-12-28 22:56:13

标签: sql sql-server sql-server-2012-express

有没有办法更有效地生成〜百万个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))

4 个答案:

答案 0 :(得分:4)

如你所说,它不是“在系统表中生成MAC地址”。它只是使用syscolumns表作为获取大量行的手段。您可以知道这一点,因为所有系统表都在FROM子句中。要插入表格,至少需要INSERTSELECT ... 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而不是intbigint而不是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;
相关问题