2016-12-02 57 views
1

考慮下面的數據庫表,它記錄了不同的對象(ID)與它的時間戳事件(狀態)的最新條目:獲取每天/ SQL優化

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 

我想用簡單的得到一個結果表鑑於

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

這裏的「狀態」是在一天最新的入門,對於這個對象至少一個事件被記錄:SQL(MS SQL)這樣的。

我現在正在使用 「外應用」 和 「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)上的索引。

+0

大,這個小變化 - 這是我太盲目看 - 由運行速度更快8倍的代碼。非常感謝! – rcvd

-1

不要從日誌表中選擇,而是寫一個觸發器,它更新一個latest_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 

然後執行從短得多lastest_run表中讀取。 這會增加寫入時的性能損失,因爲您需要兩次寫入而不是一次寫入。但是在閱讀時會給你更穩定的響應時間。如果你不需要從「運行」表中選擇,你可以避免索引它,因此兩個寫入的性能損失部分由更少的索引維護來彌補。

+1

謝謝你的建議,但這是一個商業應用程序,我不允許改變。 – rcvd

0

使用CTE可能會以最快的速度:

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