2016-08-23 47 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

相关问题