5

SQLフィドル:http ://sqlfiddle.com/#!3 / 9b459 / 6

「このイベントに参加しますか?」という質問に対する回答を含む表があります。各ユーザーは数回応答する可能性があり、すべての回答がテーブルに保存されます。通常、私たちは最新の回答にのみ関心があり、そのための効率的なクエリを構築しようとしています。SQL Server2008R2を使用しています。

1つのイベントのテーブルの内容:

テーブルの内容

Column types: int, int, datetime, bit
Primary key: (EventId, MemberId, Timestamp)

メンバー18が最初に「いいえ」と答えてから「はい」と答え、メンバー20が最初に「はい」と答えてから「いいえ」と答え、メンバー11が「いいえ」と答えてから「いいえ」と答えたことに注意してください。これらのメンバーの最初の回答を除外したいと思います。また、フィルタリングする必要のある回答が複数ある場合もあります。たとえば、ユーザーは「はい」、「はい」、「いいえ」、「はい」、「いいえ」、「いいえ」、「いいえ」と答える場合があります。

いくつかの異なるアイデアを試し、SQL Server Management Studioですべてのクエリを入力し、[推定実行プランの表示]を選択して、各クエリの合計コストをパーセントで比較することにより、それらを評価しました。それはパフォーマンスを評価するための良い方法ですか?

これまでにテストされたさまざまなクエリ:

-----------------------------------------------------------------
-- Subquery to select Answer (does not include Timestamp)
-- Cost: 63 %
-----------------------------------------------------------------
select distinct a.EventId, a.MemberId,
(
  select top 1 Answer
  from    Attendees
  where EventId   = a.EventId
  and   MemberId  = a.MemberId
  order by Timestamp desc
) as Answer
from    Attendees a
where a.EventId = 68

-----------------------------------------------------------------
-- Where with subquery to find max(Timestamp)
-- Cost: 13 %
-----------------------------------------------------------------
select a.EventId, a.MemberId, a.Timestamp, a.Answer
from     Attendees a
where  a.EventId = 68
and    a.Timestamp =
(
  select max(Timestamp)
  from     Attendees
  where  EventId  = a.EventId
  and    MemberId = a.MemberId
)
order by a.TimeStamp;

-----------------------------------------------------------------
-- Group by to find max(Timestamp)
-- Subquery to select Answer matching max(Timestamp)
-- Cost: 23 %
-----------------------------------------------------------------
select a.EventId, a.MemberId, max(a.Timestamp),
(
  select top 1 Answer
  from    Attendees
  where EventId   = a.EventId
  and   MemberId  = a.MemberId
  and   Timestamp = max(a.Timestamp)
) as Answer
from    Attendees a
where a.EventId = 68
group by a.EventId, a.MemberId
order by max(a.TimeStamp);

メンバーごとにサブクエリを使用しないようにすると便利です。最後のクエリで使用しようとしgroup byましたが、Answer列にサブクエリを使用する必要がありました。私は本当にこのようなものが欲しいのですが、それはもちろん有効なSQLではありません:

select a.EventId, a.MemberId, max(a.Timestamp), a.Answer <-- Picked from the line selected by max(a.Timestamp)
from  Attendees a
where a.EventId = 68
group by a.EventId, a.MemberId
order by max(a.TimeStamp);

効率的なクエリのための他のアイデアはありますか?


編集:

SQL Fiddleに非常に感銘を受け、実際のデータをここに入力しました: http ://sqlfiddle.com/#!3/9b459/6

4

3 に答える 3

7

SQL Server 2008は、共通テーブル式とウィンドウ関数をサポートしています。

WITH recordsList
AS
(
    SELECT  EventID, MemberID, TimeStamp, Answer,
            ROW_NUMBER() OVER (PARTITION BY EventID, MemberID
                                ORDER BY Timestamp DESC) rn
    FROM    tableName
)
SELECT  EventID, MemberID, TimeStamp, Answer
FROM    recordsList
WHERE   rn = 1
于 2013-01-25T15:01:50.467 に答える
3

私もCTEアプローチを好みますが、これが機能するはずのサブクエリを使用する別のオプションです。

SELECT T.EventId, T.MemberId, T.TimeStamp, T.Answer
FROM TableName T
 JOIN (
   SELECT EventId, MemberId, Max(Timestamp) MaxTimeStamp
   FROM TableName
   GROUP BY EventId, MemberId ) T2 ON T.EventId = T2.EventId 
    AND T.MemberId = T2.MemberId 
    AND T.TimeStamp = T2.MaxTimeStamp

そうは言っても、CTEの方がパフォーマンスが良いと思います。

編集-パフォーマンスについてはもうわかりません-ここに両方の​​SQLフィドルがあります-それぞれの実行プランを確認できます。

幸運を。

于 2013-01-25T15:08:22.253 に答える
3

もう1つのオプション

SELECT a.EventId, a.MemberId, a.Timestamp, a.Answer
FROM Attendees a
WHERE a.EventId = 68 AND EXISTS (
              SELECT 1
              FROM Attendees
              WHERE EventId = a.EventId             
              GROUP BY MemberId
              HAVING  MAX(Timestamp) = a.Timestamp                      
                      AND MemberId  = a.MemberId
              )

SQLFiddleのデモ

于 2013-01-25T16:47:54.493 に答える