sql >> Database teknologi >  >> RDS >> Sqlserver

Find samlet tid arbejdet med flere job/ordrer med overlapning/overlappende tider på hver arbejder og job/ordre

Denne forespørgsel gør også jobbet. Dens ydeevne er meget god (mens udførelsesplanen ikke ser så god ud, slår den faktiske CPU og IO mange andre forespørgsler).

Se, hvordan det fungerer i en Sql-violin .

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
;

Med et klynget indeks på WorkerID, JobStart, JobEnd, JobID , og med prøven på 7 rækker fra ovenstående violin, en skabelon for nye arbejder/job-data, der gentages nok gange til at give en tabel med 14.336 rækker, her er præstationsresultaterne. Jeg har inkluderet de andre fungerende/korrekte svar på siden (indtil videre):

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

Jeg lavede en mere udtømmende test fra en anden (langsommere) server (hvor hver forespørgsel blev kørt 25 gange, de bedste og værste værdier for hver metrik blev smidt ud, og de resterende 23 værdier blev beregnet til gennemsnittet) og fik følgende:

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

Den alternative teknik troede jeg var sikker på at forbedre tingene. Nå, det sparede 6 læsninger, men kostede meget mere CPU (hvilket giver mening). I stedet for at føre start/slut-statistikken for hvert tidsudsnit igennem til slutningen, er det bedst bare at genberegne, hvilke udsnit der skal beholdes med EXISTS mod de originale data. Det kan være, at en anden profil af få arbejdere med mange job kan ændre præstationsstatistikken for forskellige forespørgsler.

Hvis nogen vil prøve det, så brug CREATE TABLE og INSERT udsagn fra min violin og derefter køre dette 11 gange:

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
;

Jeg byggede to andre løsninger til denne forespørgsel, men den bedste med omtrent dobbelt så god ydeevne havde en fatal fejl (ikke håndterede fuldstændigt lukkede tidsintervaller korrekt). Den anden havde meget høj/dårlig statistik (som jeg vidste, men måtte prøve).

Forklaring

Brug alle endepunktstiderne fra hver række til at opbygge en særskilt liste over alle mulige tidsintervaller af interesse ved at duplikere hvert endepunktstidspunkt og derefter gruppere på en sådan måde, at hver gang parres med det næste mulige tidspunkt. Sum de forløbne minutter af disse intervaller, uanset hvor de falder sammen med enhver faktisk arbejders arbejdstid.



  1. C#:Oracle Data Type Equivalence med OracleDbType

  2. Rollback databaseændringer ved hjælp af implicitte lagringspunkter? - Oracle

  3. Udskift CHAR med VARCHAR2

  4. BESTIL AF i en SQL Server 2008-visning