2016-12-02 4 views
1

を最適化する日/ SQLにつき最新のエントリを取得する:そのタイムスタンプを持つイベントの異なるオブジェクト用(ステータス)(ID)を記録し、次のデータベーステーブルを、与えられた

ID | Date  | Time | Status 
------------------------------- 
7 | 2016-10-10 | 8:23 | Passed 
7 | 2016-10-10 | 8:29 | Failed 
7 | 2016-10-13 | 5:23 | Passed 
8 | 2016-10-09 | 5:43 | Passed 

私はプレーンを使用して結果表を取得したいですこのようなSQL(MS SQL):

ID | Date  | Status 
------------------------ 
7 | 2016-10-10 | Failed 
7 | 2016-10-13 | Passed 
8 | 2016-10-09 | Passed 

「ステータス」の日に最新のエントリで、このオブジェクトの少なくとも1つのイベントが記録されていることを考えます。

私の現在のソリューションは、 "外部適用" と "TOP(1)" のように、この使用している

SELECT DISTINCT rn.id, 
       tmp.date, 
       tmp.status 

FROM run rn OUTER apply 
    (SELECT rn2.date, tmp2.status AS 'status' 
    FROM run rn2 OUTER apply 
    (SELECT top(1) rn3.id, rn3.date, rn3.time, rn3.status 
     FROM run rn3 
     WHERE rn3.id = rn.id 
     AND rn3.date = rn2.date 
     ORDER BY rn3.id ASC, rn3.date + rn3.time DESC) tmp2 
    WHERE tmp2.status <> '') tmp 

私の知る限りのように、この外側の適用コマンドの機能を理解するよう:

For every id 
    For every recorded day for this id 
    Select the newest status for this day and this id 

をしかし、私はパフォーマンスの問題に直面しているので、私はこの解決策は適切ではないと思う。任意の提案をどのようにこの問題を解決するか、SQLを最適化する方法?

答えて

1

コードが複雑すぎるようです。なぜこれをしないのですか?

SELECT r.id, r.date, r2.status 
FROM run r OUTER APPLY 
    (SELECT TOP 1 r2.* 
     FROM run r2 
     WHERE r2.id = r.id AND r2.date = r.date AND r2.status <> '' 
     ORDER BY r2.time DESC 
    ) r2; 

パフォーマンスについては、run(id, date, status, time)のインデックスを推奨します。はるかに短いlastest_runテーブルから読み込む

CREATE TRIGGER tr_run_insert ON run FOR INSERT AS 
BEGIN 
    UPDATE latest_run SET Status=INSERTED.Status WHERE ID=INSERTED.ID AND Date=INSERTED.Date 
    IF @@ROWCOUNT = 0 
     INSERT INTO latest_run (ID,Date,Status) SELECT (ID,Date,Status) FROM INSERTED 
END 

が次に実行します。

+0

グレート、この小さな変更は8倍高速動作するコードを作りました。どうもありがとう! – rcvd

-1

は次のようにlatest_runテーブルを更新トリガーを作成し、代わりに、ログテーブルから選択しないでください。 これは、1つではなく2つの書き込みが必要になるため、書き込みにパフォーマンスのペナルティを追加します。しかし、読んでもずっと安定した応答時間が得られます。また、「実行」テーブルからSELECTを実行する必要がない場合は、インデックス作成を避けることができます。したがって、2つの書き込みのパフォーマンス上の不利益は、インデックスの保守が少なくて済みます。おそらく最速となりますCTEを使用して

+1

この提案をありがとうございますが、私は変更が許可されていない商用アプリケーションです。 – rcvd

0

: - 私は見てあまりにも盲目だった -

with cte as 
(
    select ID, Date, Status, row_number() over (partition by ID, Date order by Time desc) rn 
    from run 
) 
select ID, Date, Status 
from cte 
where rn = 1 
関連する問題