1

我受限于遗留数据库结构,需要一些统计结果。以下查询有效,但效率低下且速度慢...

SELECT various, other, native, columns,
    (SELECT client FROM clients WHERE id = clientid) AS client,
    (SELECT name FROM categories WHERE id = (SELECT categoryid FROM clients WHERE id = clientid)) AS category,
    (SELECT fullname FROM staff WHERE id = producerid) AS producer,
    ISNULL((SELECT SUM(amount) FROM JobsVoiceWork v WHERE v.jobid = j.id),0) AS voicecosts,
    (SELECT COUNT(*) FROM Scripts s WHERE s.jobid = j.id) AS numberofscriptscompleted,
    ISNULL((SELECT SUM(duration) FROM TimeLog WHERE jobid = j.id),0)/60 AS totaltime,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 3 AND jobpart = 'Add'),0)/60 AS PartAdd,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 3 AND jobpart = 'Update'),0)/60 AS PartUpdate,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 3 AND jobpart = 'Produce'),0)/60 AS PartProduce,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 3 AND jobpart = 'Amend'),0)/60 AS PartAmend,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 4),0)/60 AS EditProducerError,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 8),0)/60 AS EditVoiceError,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 1),0)/60 AS EditClientError,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 2),0)/60 AS EditEntryError,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 5),0)/60 AS EditPronunciation,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 6),0)/60 AS EditRemixRequest,
    ISNULL((SELECT SUM(duration)  FROM TimeLog WHERE jobid = j.id AND jobeditid = 7),0)/60 AS EditRevoiceRequest
FROM Jobs j

我展示了查询的简化版本,但我包含了重复的子查询以清楚地证明效率低下。我尝试了各种表连接方案,但无法提高性能。

看起来应该可以改进。有办法吗?

4

3 回答 3

4

您可以使用CASE语句来消除多余的子查询,例如:

SELECT various, other, native, columns,
    (SELECT client FROM clients WHERE id = clientid) AS client,
    (SELECT name FROM categories WHERE id = (SELECT categoryid FROM clients WHERE id = clientid)) AS category,
    (SELECT fullname FROM staff WHERE id = producerid) AS producer,
    ISNULL((SELECT SUM(amount) FROM JobsVoiceWork v WHERE v.jobid = j.id),0) AS voicecosts,
    (SELECT COUNT(*) FROM Scripts s WHERE s.jobid = j.id) AS numberofscriptscompleted,
    ISNULL(SUM(t.duration),0)/60 AS totaltime,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 3 AND t.jobpart = 'Add' THEN t.duration ELSE 0 END),0)/60 AS PartAdd,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 3 AND t.jobpart = 'Update' THEN t.duration ELSE 0 END),0)/60 AS PartUpdate,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 3 AND t.jobpart = 'Produce' THEN t.duration ELSE 0 END),0)/60 AS PartProduce,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 3 AND t.jobpart = 'Amend' THEN t.duration ELSE 0 END),0)/60 AS PartAmend,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 4 THEN t.duration ELSE 0 END),0)/60 AS EditProducerError,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 8 THEN t.duration ELSE 0 END),0)/60 AS EditVoiceError,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 1 THEN t.duration ELSE 0 END),0)/60 AS EditClientError,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 2 THEN t.duration ELSE 0 END),0)/60 AS EditEntryError,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 5 THEN t.duration ELSE 0 END),0)/60 AS EditPronunciation,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 6 THEN t.duration ELSE 0 END),0)/60 AS EditRemixRequest,
    ISNULL(SUM(CASE WHEN  t.jobeditid = 7 THEN t.duration ELSE 0 END),0)/60 AS EditRevoiceRequest
    FROM Jobs j
    LEFT JOIN Timelog t
       ON j.id = t.jobid
于 2013-07-11T03:39:03.793 回答
1

Try this one -

SELECT various, other, native, columns,
    c.client,
    c2.name AS category,
    s.fullname AS producer,
    ISNULL(v.amount, 0) AS voicecosts,
    s3.numberofscriptscompleted,
    ISNULL(SUM(t.duration),0)/60 AS totaltime,
    ISNULL(SUM(CASE WHEN t.jobeditid = 3 AND t.jobpart = 'Add' THEN t.duration END),0)/60 AS PartAdd,
    ISNULL(SUM(CASE WHEN t.jobeditid = 3 AND t.jobpart = 'Update' THEN t.duration END),0)/60 AS PartUpdate,
    ISNULL(SUM(CASE WHEN t.jobeditid = 3 AND t.jobpart = 'Produce' THEN t.duration END),0)/60 AS PartProduce,
    ISNULL(SUM(CASE WHEN t.jobeditid = 3 AND t.jobpart = 'Amend' THEN t.duration END),0)/60 AS PartAmend,
    ISNULL(SUM(CASE WHEN t.jobeditid = 4 THEN t.duration END),0)/60 AS EditProducerError,
    ISNULL(SUM(CASE WHEN t.jobeditid = 8 THEN t.duration END),0)/60 AS EditVoiceError,
    ISNULL(SUM(CASE WHEN t.jobeditid = 1 THEN t.duration END),0)/60 AS EditClientError,
    ISNULL(SUM(CASE WHEN t.jobeditid = 2 THEN t.duration END),0)/60 AS EditEntryError,
    ISNULL(SUM(CASE WHEN t.jobeditid = 5 THEN t.duration END),0)/60 AS EditPronunciation,
    ISNULL(SUM(CASE WHEN t.jobeditid = 6 THEN t.duration END),0)/60 AS EditRemixRequest,
    ISNULL(SUM(CASE WHEN t.jobeditid = 7 THEN t.duration END),0)/60 AS EditRevoiceRequest
FROM Jobs j
JOIN clients c ON j.id = c.clientid
JOIN categories c2 ON c2.id = c.clientid
JOIN staff s ON j.id = s.producerid
LEFT JOIN (
     SELECT v.jobid, amount = SUM(amount) 
     FROM JobsVoiceWork v 
     GROUP BY v.jobid
) v ON v.jobid = j.id
JOIN (
     SELECT s.jobid, numberofscriptscompleted = COUNT(*) 
     FROM Scripts s 
     GROUP BY s.jobid
) s3 ON s3.jobid = j.id
LEFT JOIN Timelog t ON j.id = t.jobid
--GROUP BY ...
于 2013-07-11T06:23:11.607 回答
0

我不会保证这会更好,它可能会更糟 - 但它是一种不同的方法,可能会有所帮助。试一试,看看有没有用。

首先,我正在编译一个临时表,将所有 jobs.id + timelog.jobeditid + 值的持续时间相加,如果 jobeditid 为 3,则 timelog.jobpart:

SELECT j.id, tl.jobeditid, case when tl.jobeditid = 3 then tl.jobpart else '' end as [JobPart], (Sum(tl.duration)/60) as AdjTotalDuration
INTO #t
FROM Jobs J CROSS JOIN TimeLog tl
GROUP BY j.id, tl.jobeditid, case when tl.jobeditid = 3 then tl.jobpart else '' end;

现在我已经大大简化了您的查询,以多种不同的方式使用这个临时表;我还将 select 子句中的大部分子查询移动到 from 子句中的连接表中:

SELECT various, other, native, columns, c.Client, cg.name as [Category], s.fullname as Producer,
  isnull(v.TotalAmount, 0) as voicecosts, (SELECT COUNT(*) FROM Scripts s WHERE s.jobid = j.id) AS numberofscriptscompleted,
  isnull((SELECT SUM(AdjTotalDuration) FROM #t WHERE jobid = j.id),0) AS TotalTime,
  t3a.AdjTotalDuration as PartAdd,
  t3u.AdjTotalDuration as PartUpdate,
  t3p.AdjTotalDuration as PartProduce,
  t3m.AdjTotalDuration as PartAmend,
  t4.AdjTotalDuration  as EditProducerError,
  t8.AdjTotalDuration  as EditVoiceError,
  t1.AdjTotalDuration  as EditClientError,
  t2.AdjTotalDuration  as EditEntryError,
  t5.AdjTotalDuration  as EditPronunciation,
  t6.AdjTotalDuration  as EditRemixRequest,
  t7.AdjTotalDuration  as EditRevoiceRequest
FROM Jobs j 
  join clients c on j.ClientID = c.ID
  join categories cg on c.CategoryID = cg.ID
  join staff s on j.ProducerID = s.ID
  left join (select jobid, sum(amount) as TotalAmount from JobsVoiceWork group by jobid) v on j.id = v.jobid
  left join (select * from #t where id = j.id and jobeditid = 3 and jobpart = 'Add') t3a
  left join (select * from #t where id = j.id and jobeditid = 3 and jobpart = 'Update') t3u 
  left join (select * from #t where id = j.id and jobeditid = 3 and jobpart = 'Produce') t3p
  left join (select * from #t where id = j.id and jobeditid = 3 and jobpart = 'Amend') t3m 
  left join (select * from #t where id = j.id and jobeditid = 4) t4 
  left join (select * from #t where id = j.id and jobeditid = 8) t8 
  left join (select * from #t where id = j.id and jobeditid = 1) t1 
  left join (select * from #t where id = j.id and jobeditid = 2) t2 
  left join (select * from #t where id = j.id and jobeditid = 5) t5 
  left join (select * from #t where id = j.id and jobeditid = 6) t6 
  left join (select * from #t where id = j.id and jobeditid = 7) t7; 

这会改善它吗?它会使情况变得更糟吗?

如果确实改善了,请标记为答案。

问候约翰

于 2013-07-11T05:12:04.923 回答