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

複数のジョブ / オーダーで作業した合計時間を、各作業者とジョブ / オーダーでオーバーラップ / オーバーラップした時間で検索します

    このクエリも同様に機能します。そのパフォーマンスは非常に優れています (実行計画はそれほど良くないように見えますが、実際の CPU と IO は他の多くのクエリを上回っています)。

    Sql Fiddle での動作を確認 .

    WITH Times AS (
       SELECT DISTINCT
          H.WorkerID,
          T.Boundary
       FROM
          dbo.JobHistory H
          CROSS APPLY (VALUES (H.JobStart), (H.JobEnd)) T (Boundary)
    ), Groups AS (
       SELECT
          WorkerID,
          T.Boundary,
          Grp = Row_Number() OVER (PARTITION BY T.WorkerID ORDER BY T.Boundary) / 2
       FROM
          Times T
          CROSS JOIN (VALUES (1), (1)) X (Dup)
    ), Boundaries AS (
       SELECT
          G.WorkerID,
          TimeStart = Min(Boundary),
          TimeEnd = Max(Boundary)
       FROM
          Groups G
       GROUP BY
          G.WorkerID,
          G.Grp
       HAVING
          Count(*) = 2
    )
    SELECT
       B.WorkerID,
       WorkedMinutes = Sum(DateDiff(minute, 0, B.TimeEnd - B.TimeStart))
    FROM
       Boundaries B
    WHERE
       EXISTS (
          SELECT *
          FROM dbo.JobHistory H
          WHERE
             B.WorkerID = H.WorkerID
             AND B.TimeStart < H.JobEnd
             AND B.TimeEnd > H.JobStart
       )
    GROUP BY
       WorkerID
    ;
    

    WorkerID, JobStart, JobEnd, JobID にクラスター化インデックスを使用 、および上記のサンプル 7 行を使用して、14,336 行のテーブルを生成するのに十分な回数繰り返された新しいワーカー/ジョブ データのテンプレートをフィドルします。パフォーマンス結果は次のとおりです。ページに他の有効な/正しい回答を含めました (これまでのところ):

    Author  CPU  Elapsed  Reads   Scans
    ------  ---  -------  ------  -----
      Erik  157    166      122       2
    Gordon  375    378    106964  53251
    

    別の (より遅い) サーバーからより徹底的なテストを行い (各クエリを 25 回実行し、各メトリックの最良値と最悪値を除外し、残りの 23 個の値を平均しました)、次の結果を得ました:

    Query     CPU   Duration  Reads   Notes
    --------  ----  --------  ------  ----------------------------------
    Erik 1    215   231       122     query as above
    Erik 2    326   379       116     alternate technique with no EXISTS
    Gordon 1  578   682       106847  from j
    Gordon 2  584   673       106847  from dbo.JobHistory
    

    確実に改善できると思った代替テクニック。 6 回の読み取りを節約できましたが、CPU のコストが大幅に増加しました (これは理にかなっています)。各タイムスライスの開始/終了統計を最後まで実行する代わりに、EXISTS でどのスライスを保持するかを再計算するのが最善です 元のデータに対して。多くのジョブを持つ少数のワーカーのプロファイルが異なると、さまざまなクエリのパフォーマンス統計が変わる可能性があります。

    誰かが試してみたい場合は、CREATE TABLE を使用してください そして INSERT 私のフィドルからのステートメントを実行し、これを 11 回実行します。

    INSERT dbo.JobHistory
    SELECT
       H.JobID + A.MaxJobID,
       H.WorkerID + A.WorkerCount,
       DateAdd(minute, Elapsed + 45, JobStart),
       DateAdd(minute, Elapsed + 45, JobEnd)
    FROM
       dbo.JobHistory H
       CROSS JOIN (
          SELECT
             MaxJobID = Max(JobID),
             WorkerCount = Max(WorkerID) - Min(WorkerID) + 1,
             Elapsed = DateDiff(minute, Min(JobStart), Min(JobEnd))
          FROM dbo.JobHistory
       ) A
    ;
    

    このクエリに対して他に 2 つのソリューションを作成しましたが、パフォーマンスが約 2 倍の最良のソリューションには致命的な欠陥がありました (完全に囲まれた時間範囲を正しく処理していません)。もう 1 つは非常に高い/悪い統計値でした (わかっていましたが、試してみる必要がありました)。

    説明

    各行のすべての終点時刻を使用して、各終点時刻を複製し、次に可能な時刻と毎回ペアになるようにグループ化することにより、対象となる可能性のあるすべての時刻範囲の個別のリストを作成します。労働者の実際の作業時間と一致する場合はいつでも、これらの範囲の経過分を合計します。



    1. SQL ServerのPARSE()とTRY_PARSE()の違い:違いは何ですか?

    2. SQL Server 2008ManagementStudioがクエリの構文をチェックしていません

    3. MySQLデータベースに1対多の関係を保存する方法は?

    4. SQLServer2008でのPIVOTの使用