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 に答える
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 に答える