2016-08-23 59 views
1

我正在查詢一張對每個記錄有多個修訂版的表,但不存儲每條記錄的版本號。我必須從「接觸」日期中推導出它。什麼是確定記錄最新修訂的最有效方法?

我想檢索最新版本。

我在兩種方法之間揮之不去:ROW_NUMBER()LEFT OUTER JOIN但我不確定哪一個會更好。也許這取決於上下文,但我不確定要考慮哪些因素。我不知道這些表格上的索引。

這兩種方法在性能上是否存在顯着差異?

ROW_NUMBER()

SELECT * 
FROM 
(
    SELECT h.header_id, 
      h.touched_on, 
      ROW_NUMBER() OVER (PARTITION BY h.header_id ORDER BY h.touched_on DESC) AS revision 
    FROM header h 
    JOIN event e ON h.serial_no = e.serial_no 
    WHERE h.touched_on BETWEEN @startDate AND @endDate 
) noms 
WHERE noms.revision = 1 

LEFT JOIN

SELECT h.header_id, 
     h.touched_on, 
FROM header h 
LEFT OUTER JOIN header h2 ON h2.header_id = h.header_id AND h2.touched_on > h.touched_on 
JOIN event e ON h.serial_no = e.serial_no 
WHERE h.touched_on BETWEEN @startDate AND @endDate 
AND h2.header_id IS NULL 
+7

我的意思是,你有數據,可以測試兩個查詢。無論如何,它們不是等價的,第二個不會返回你似乎想要的數據 – Lamak

+5

你看過兩種選項的查詢計劃嗎?一個人明顯比另一個人長嗎? – Siyual

+1

首先,它們是不同的查詢。第二個可能爲header_id返回多個原始數據。 – Serg

回答

0

不知道該怎麼會告訴你你的LEFT JOIN的查詢,考慮CROSS取代它適用於:

SELECT DISTINCT 
      h2.header_id, 
      h2.touched_on 
FROM header h 
CROSS APPLY (
    SELECT TOP 1 * 
    FROM header 
    WHERE header_id = h.header_id 
     and touched_on BETWEEN @startDate AND @endDate 
    ORDER BY touched_on DESC) as h2 
JOIN [event] e ON h2.serial_no = e.serial_no 
WHERE h.touched_on BETWEEN @startDate AND @endDate 
0

我優先使用Common Table Expression: -

SET STATISTICS IO ON; 
SET STATISTICS TIME ON; 
WITH HeaderEvent 
    AS (SELECT h.header_id, 
       h.touched_on, 
       RowNumber = ROW_NUMBER() OVER(PARTITION BY h.header_id ORDER BY h.touched_on DESC) 
     FROM header h 
       JOIN event e ON h.serial_no = e.serial_no 
     WHERE h.touched_on BETWEEN @startDate AND @endDate) 
    SELECT header_id, 
      touched_on 
    FROM HeaderEvent 
    WHERE RowNumber = 1; 

比較性能包括以下之前運行的每個查詢來比較指標: -

SET STATISTICS IO ON; 
SET STATISTICS TIME ON; 

您也可以調查Temporal Tables功能(SQL服務器2016只)數據的有效存儲版本歷史替代。

+0

這與第一個查詢發佈相同 – Lamak

1

如果你想獲取當前(最新)版本一個特定的鍵,然後很簡單:

SELECT TOP(1) ... 
    FROM <table> 
    WHERE key = @key 
    ORDER BY touched_on DESC; 

爲了使這個高效您的表應該由(key, touched_on)羣集。

但是,要檢索行(或全部)的集合的當前(最新)版本,那麼該任務很困難,至少可以說。 A 更好的設計是將表拆分成兩個,一個保持當前的行和一個保存所有的歷史。這正是SQL Server 2016中的Temporal Tables所做的,這是what PostgreSQL does,這是DB2所做的。基本上沒有實現提供時間旅行,通過將該行的所有版本存儲在同一個表中,因爲它查詢當前數據令人難以置信的昂貴

你看,你的設計是已知是有問題和低效。解決根本原因的問題要好得多,並將數據分成<table_current><table_history>

+0

有道理,我同意,但不幸的是,它不是我的數據庫來更改,我只是查詢它。 – Tedderz

相關問題