sql >> データベース >  >> RDS >> Database

ループのないセットまたはシーケンスを生成する–パート2

    前回の投稿では、1から1,000までの連続した数字のシーケンスを生成する方法について話しました。次に、次のレベルのスケールについて説明します。50,000と1,000,000の数値のセットを生成します。

    50,000個の数字のセットを生成する

    このシリーズを始めたとき、私はさまざまなアプローチがより大きな数のセットにどのようにスケーリングするのか本当に興味がありました。ローエンドでは、sys.all_objectsを使用して、私のお気に入りのアプローチを見つけて少しがっかりしました。 –最も効率的な方法ではありませんでした。しかし、これらのさまざまな手法を50,000行に拡張するにはどうすればよいでしょうか。

      数値表

      1,000,000行のNumbersテーブルをすでに作成しているため、このクエリは実質的に同じままです:

      SELECT TOP (50000) n FROM dbo.Numbers ORDER BY n;

      計画:

      spt_values

      spt_valuesには最大2,500行しかないため 、セットジェネレータのソースとして使用する場合は、もう少しクリエイティブにする必要があります。より大きなテーブルをシミュレートする1​​つの方法は、CROSS JOINです。 それ自体に対して。これを生で実行すると、最大2,500行の2乗(600万行以上)になります。必要な行は50,000行だけで、約224行の2乗が必要です。だから私たちはこれを行うことができます:

      ;WITH x AS 
      (
        SELECT TOP (224) number FROM [master]..spt_values
      )
      SELECT TOP (50000) n = ROW_NUMBER() OVER (ORDER BY x.number) 
      FROM x CROSS JOIN x AS y
      ORDER BY n;

      これは、このバリエーションと同等ですが、より簡潔であることに注意してください。

      SELECT TOP (50000) n = ROW_NUMBER() OVER (ORDER BY x.number) 
      FROM 
      (SELECT TOP (224) number FROM [master]..spt_values) AS x
      CROSS JOIN
      (SELECT TOP (224) number FROM [master]..spt_values) AS y
      ORDER BY n;

      どちらの場合も、計画は次のようになります。

      sys.all_objects

      spt_valuesのように 、sys.all_objects 単独では50,000行の要件を完全には満たしていないため、同様のCROSS JOINを実行する必要があります。 。

      ;;WITH x AS 
      (
        SELECT TOP (224) [object_id] FROM sys.all_objects
      )
      SELECT TOP (50000) n = ROW_NUMBER() OVER (ORDER BY x.[object_id]) 
      FROM x CROSS JOIN x AS y 
      ORDER BY n;

      計画:

      スタックCTE

      正確に50,000行を取得するには、スタックされたCTEをわずかに調整するだけです。

      ;WITH e1(n) AS
      (
          SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
          SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
          SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
      ), -- 10
      e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
      e3(n) AS (SELECT 1 FROM e2 CROSS JOIN e2 AS b), -- 100*100
      e4(n) AS (SELECT 1 FROM e3 CROSS JOIN (SELECT TOP 5 n FROM e1) AS b)  -- 5*10000
        SELECT n = ROW_NUMBER() OVER (ORDER BY n) FROM e4 ORDER BY n;

      計画:

      再帰的CTE

      再帰CTEから50,000行を取得するには、さらに重要性の低い変更が必要です。WHEREを変更します。 句を50,000に変更し、MAXRECURSIONを変更します ゼロにするオプション。

      ;WITH n(n) AS
      (
          SELECT 1
          UNION ALL
          SELECT n+1 FROM n WHERE n < 50000
      )
      SELECT n FROM n ORDER BY n
      OPTION (MAXRECURSION 0);

      計画:

      この場合、ソートに警告アイコンがあります。私のシステムでは、ソートがtempdbに流出する必要がありました。システムに流出が見られない場合もありますが、これはこの手法に必要なリソースに関する警告であるはずです。

      パフォーマンス

      最後の一連のテストと同様に、コールドキャッシュとウォームキャッシュの両方、および圧縮と非圧縮の両方を使用したNumbersテーブルを含む各手法を比較します。


      ミリ秒単位のランタイムで、50,000個の連続した数値を生成します>

      より良い視覚を得るために、このテストでは完全な犬であり、結果を歪める再帰CTEを削除しましょう:


      実行時間(ミリ秒単位)で、50,000個の連続した数値を生成します(再帰を除く) CTE)

      1,000行では、クエリはそれぞれ8ページと9ページを読み取るだけでよいため、圧縮と非圧縮の違いはわずかでした。 50,000行では、ギャップが少し広がります。74ページ対113です。ただし、データを解凍するための全体的なコストは、I/Oの節約を上回っているようです。したがって、50,000行の場合、非圧縮の数値テーブルが連続したセットを導出するための最も効率的な方法のように見えますが、確かに、利点はわずかです。

    1,000,000個の数値のセットを生成する

    これほど大きな数の連続したセットが必要になるような多くのユースケースを想像することはできませんが、完全を期すために、そしてこの規模でいくつかの興味深い観察を行ったので、それを含めたかったのです。

      数値表

      ここで驚くことはありません。クエリは次のようになります:

      SELECT TOP 1000000 n FROM dbo.Numbers ORDER BY n;

      TOP 厳密に必要というわけではありませんが、これは、Numbersテーブルと目的の出力の行数が同じであることがわかっているためです。計画は以前のテストと非常によく似ています:

      spt_values

      CROSS JOINを取得するには 1,000,000行になるので、1,000行を2乗する必要があります:

      ;WITH x AS 
      (
        SELECT TOP (1000) number FROM [master]..spt_values
      )
      SELECT n = ROW_NUMBER() OVER (ORDER BY x.number) 
      FROM x CROSS JOIN x AS y ORDER BY n;
      >

      計画:

      sys.all_objects

      ここでも、1,000行の外積が必要です:

      ;WITH x AS 
      (
        SELECT TOP (1000) [object_id] FROM sys.all_objects
      )
      SELECT n = ROW_NUMBER() OVER (ORDER BY x.[object_id]) 
      FROM x CROSS JOIN x AS y ORDER BY n;

      計画:

      スタックCTE

      スタックされたCTEの場合、CROSS JOINのわずかに異なる組み合わせが必要です。 s 1,000,000行に到達するには:

      ;WITH e1(n) AS
      (
          SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
          SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
          SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
      ), -- 10
      e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
      e3(n) AS (SELECT 1 FROM e1 CROSS JOIN e2 AS b), -- 10*100
      e4(n) AS (SELECT 1 FROM e3 CROSS JOIN e3 AS b)  -- 1000*1000
        SELECT n = ROW_NUMBER() OVER (ORDER BY n) FROM e4 ORDER BY n;

      計画:

      この行サイズでは、スタックされたCTEソリューションが並列になっていることがわかります。そこで、MAXDOP 1を使用したバージョンも実行しました 以前と同様の計画形状を取得し、並列処理が本当に役立つかどうかを確認するには:

      再帰CTE

      再帰CTEにも、わずかな変更があります。 WHEREのみ 条項を変更する必要があります:

      ;WITH n(n) AS
      (
          SELECT 1
          UNION ALL
          SELECT n+1 FROM n WHERE n < 1000000
      )
      SELECT n FROM n ORDER BY n
      OPTION (MAXRECURSION 0);

      計画:

      パフォーマンス

      ここでも、再帰CTEのパフォーマンスがひどいことがわかります。


      1,000,000個の連続した数値を生成するための実行時間(ミリ秒単位)>

      グラフからその外れ値を削除すると、パフォーマンスに関するより良い画像が得られます:


      実行時間(ミリ秒単位)で、1,000,000個の連続した数値を生成します(再帰を除く) CTE)

      ここでも、圧縮されていないNumbersテーブル(少なくともウォームキャッシュを使用)が勝者と見なされますが、このスケールでも違いはそれほど顕著ではありません。

    続く…

    数列を生成するためのいくつかのアプローチを徹底的に調査したので、日付に移ります。このシリーズの最後の投稿では、カレンダーテーブルの使用を含む、セットとしての日付範囲の構築と、これが便利ないくつかのユースケースについて説明します。

    [パート1|パート2|パート3]

    付録:行数

    正確な数の行を生成しようとしていない可能性があります。代わりに、多くの行を生成する簡単な方法が必要な場合があります。以下は、単にSELECTするだけで、さまざまな行数を取得できるカタログビューの組み合わせのリストです。 WHEREなし 句。これらの数値は、RTMまたはサービスパックのどちらを使用しているか(一部のシステムオブジェクトが追加または変更されるため)、および空のデータベースがあるかどうかによっても異なることに注意してください。

    ソース 行数
    SQL Server 2008 R2 SQL Server 2012 SQL Server 2014
    master..spt_values

    2,508

    2,515 2,519
    master..spt_values CROSS JOIN master..spt_values

    6,290,064

    6,325,225 6,345,361
    sys.all_objects

    1,990

    2,089 2,165
    sys.all_columns

    5,157

    7,276 8,560
    sys.all_objects CROSS JOIN sys.all_objects

    3,960,100

    4,363,921 4,687,225
    sys.all_objects CROSS JOIN sys.all_columns

    10,262,430

    15,199,564 18,532,400
    sys.all_columns CROSS JOIN sys.all_columns

    26,594,649

    52,940,176 73,273,600

    表1:さまざまなカタログビュークエリの行数


    1. SQLServerの文字列からすべてのスペースを削除します

    2. データは、sqliteのすべてのテーブルではなく、特定のテーブルの日付から入力されます

    3. SQL Serverが2つの整数を除算した結果を四捨五入するのはなぜですか?

    4. SQLServerはCSVを複数の行に分割します