1

〜百万のMACアドレスをより効率的に生成する方法はありますか?

これが私が行っていることですが、100万個のMACアドレスを生成してテーブルに挿入するのに約10分かかります。

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

4 に答える 4

4

あなたが言うように、それは「システムテーブルにMACアドレスを生成する」ことではありません。syscolumns単に多くの行を取得する手段としてテーブルを使用しているだけです。FROMすべてのシステムテーブルが句に含まれているため、これを知ることができます。テーブルに挿入するには、少なくともINSERTまたはが必要SELECT ... INTOです。

高速である理由は、SQLServerが「行ベース」の操作用に最適化されているためです。エンジンの内部では、もちろん各行をループする必要がありますが、大幅に最適化されています。代わりに、T-SQLを手続き型言語として扱い、各項目を一度に1つずつループすると、それらの最適化を使用できず、まったく異なる種類の実行コンテキストで各ステートメントを一度に1つずつ実行する必要があります。

syscolumnsテーブル自体は無意味です。たくさんの行があることが保証されているので、価値があります。これは、多くの行を持つ任意のテーブルである可能性があります。FROM句内のテーブルは、デカルト積(多くの行を意味します)を取得するために相互結合されているため、Row_Number()関数は、 1から1,000,000。

必要に応じて、「実際の」テーブルにまったくヒットしないこのようなアプローチを使用できます。これは、同じように、またはより速く実行されるはずです。実行しているのは、イニシャルを取得し、SELECT 1 UNION ALL SELECT 1繰り返し実行することで4.3ビリオン行に変換CROSS JOINすることです(ただし、古いスタイルの構文はFROM Table1, Table2同じですFROM Table1 CROSS JOIN Table2が短いものを使用します)。

私はSQL2008で以下をテストしましたが、完全に機能します。SQL Serverでは3秒かかります(現時点ではSQL Fiddleが誤ってエラーをスローしているため、管理者にメールを送信しました)。

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

ただし、これがSQL Server 2012のExpressエディションで機能するかどうかは100%わかりません。このバージョンを使用しても実際には問題はありません。ステートメントsyscolumnsを追加し、いくつかの問題を修正する必要があります(ではなくの代わりに) 。各テーブルの後に追加する(またはクエリの前と後に使用する)ことで、パフォーマンスを向上させることができることに注意してください。このクエリも非常にうまく機能します(私のサーバーでは2秒)。INSERTintbigintbinary(8)binary(6)WITH (NOLOCK)syscolumnsSET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDSET TRANSACTION ISOLATION LEVEL READ COMMITTED

DECLARE
   @StartRange bigint = 0x0004A500114B,
   @EndRange bigint = 0x0004A50F11FF;

INSERT Mac_Address (MacAddress) -- Add this line
SELECT Convert(binary(6), N + @StartRange - 1) 
FROM
(
    SELECT N = Row_Number() OVER (ORDER BY (SELECT 1))
    FROM
       syscolumns WITH (NOLOCK),
       syscolumns a WITH (NOLOCK),
       syscolumns b WITH (NOLOCK),
       syscolumns c WITH (NOLOCK)
) b
WHERE N <= @EndRange - @StartRange + 1;
于 2012-12-28T23:04:19.633 に答える
1

以下は単純で、オンラインSqlFiddleで1分ほどで実行されます。

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;
于 2012-12-28T23:24:55.977 に答える
1

2番目のスニペットは何も挿入していません。整数を生成するために、syscolumnsテーブルの(それ自体と交差結合された)行番号のみを使用します。

これには他のテーブルを使用できます(十分な行数があるか、それを生成するのに十分な回数結合している場合)

于 2012-12-28T23:01:58.833 に答える
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))
于 2012-12-28T23:04:22.887 に答える