sql >> Databáze >  >> RDS >> Sqlserver

Najděte celkový čas odpracovaný s více úlohami / zakázkami s překrýváním / překrývajícími se časy na každého pracovníka a zakázku / zakázku

Tento dotaz také funguje. Jeho výkon je velmi dobrý (zatímco plán provádění nevypadá tak skvěle, skutečný CPU a IO porazí mnoho dalších dotazů).

Podívejte se, jak to funguje v 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
;

Se seskupeným indexem na WorkerID, JobStart, JobEnd, JobID a s ukázkou 7 řádků z výše uvedených houslí šablony pro data nového pracovníka/úlohy, která se opakuje dostatečně často, aby se získala tabulka se 14 336 řádky, zde jsou výsledky výkonu. Další funkční/správné odpovědi jsem zahrnul na stránku (zatím):

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

Provedl jsem podrobnější test z jiného (pomalejšího) serveru (kde byl každý dotaz spuštěn 25krát, nejlepší a nejhorší hodnoty pro každou metriku byly vyhozeny a zbývajících 23 hodnot bylo zprůměrováno) a dostal jsem následující:

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

Alternativní technika, o které jsem si myslel, že věci zlepší. No, ušetřilo to 6 čtení, ale stálo to mnohem víc CPU (což dává smysl). Namísto přenášení počáteční/koncové statistiky každého časového řezu až do konce je nejlepší jednoduše přepočítat, které řezy ponechat, pomocí EXISTS oproti původním údajům. Je možné, že odlišný profil několika málo pracovníků s mnoha zaměstnáními by mohl změnit statistiky výkonu pro různé dotazy.

V případě, že by to chtěl někdo vyzkoušet, použijte CREATE TABLE a INSERT výpisy z mých houslí a pak to spusťte 11krát:

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
;

Na tento dotaz jsem postavil dvě další řešení, ale to nejlepší s přibližně dvojnásobným výkonem mělo fatální chybu (nesprávné zpracování plně uzavřených časových rozsahů). Druhý měl velmi vysoké/špatné statistiky (což jsem věděl, ale musel jsem to zkusit).

Vysvětlení

Pomocí všech časů koncových bodů z každého řádku vytvořte zřetelný seznam všech možných časových rozsahů zájmu duplikováním každého koncového času a následným seskupením tak, aby se pokaždé spárovalo s dalším možným časem. Sečtěte uplynulé minuty těchto rozsahů, ať se shodují s jakoukoli skutečnou pracovní dobou pracovníka.



  1. Vztahy mezi tabulkami MyISAM Engine (MySQL)

  2. Objekty sady dotazů Django vracejí žádné místo 0, přestože databáze má jako hodnotu pole uloženu 0

  3. Jak mohu získat počet záznamů ovlivněných uloženou procedurou?

  4. Jak udržovat data netříděná?