Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Намерете общото време, отработено с множество задачи/поръчки с припокриване/припокриващи се времена за всеки работник и работа/поръчка

Тази заявка също върши работа. Производителността му е много добра (докато планът за изпълнение не изглежда толкова страхотен, действителният процесор и 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 четения, но струва много повече процесор (което има смисъл). Вместо да пренасяте статистическите данни за начало/край на всеки времеви отрязък до края, най-добре е просто да преизчислите кои отрязъци да запазите с 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
;

Създадох две други решения на тази заявка, но най-доброто с около двойно по-висока производителност имаше фатален недостатък (неправилно обработване на напълно затворени времеви диапазони). Другият имаше много висока/лоша статистика (което знаех, но трябваше да опитам).

Обяснение

Използвайки всички крайни времена от всеки ред, изградете отделен списък от всички възможни времеви диапазони, които представляват интерес, като дублирате всяко време на крайната точка и след това групирате по такъв начин, че да сдвоите всяко време със следващото възможно време. Сумирайте изминалите минути от тези диапазони, където съвпадат с действителното работно време на всеки работник.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Проблем при динамично завъртане + sql сървър 2005

  2. Подреждането на sqlserver означава ли, че имената на колоните трябва да са правилни с главни и малки букви? И как да се справим с това

  3. Преброяване на броя на редовете, върнати от заявка за избор

  4. Вмъкване на данни от DataGridView в база данни

  5. SQL Server 2005:Импортиране на данни от SQL Server 2000