由Max

2011-10-03 54 views
1

我有一個簡單的表中選擇多行帶有「版本」方案:由Max

Version | PartKey1 | PartKey2 | Value 
    1 | 0  | 0  | foo 
    2 | 0  | 0  | bar 
    1 | 1  | 0  | foobar 

此表中(約100萬行的完整版)。在開始時它會加載一個包含完整快照的版本1,隨着時間的推移會增加更新,但我們希望保留舊版本,因此它們會添加一個遞增的「版本」編號(此處爲2)。

讀取數據時,我希望能夠指定一個最大的版本,我想,如果可能的話,只檢索「行」我感興趣的

例如:指定2爲最高版本,我想在上面的表中檢索只有2行的查詢:

Version | PartKey1 | PartKey2 | Value 
    2 | 0  | 0  | bar 
    1 | 1  | 0  | foobar 

行:

1 | 0  | 0  | foo 

被丟棄,因爲該版本2這一行是是最近的。

我想知道如果這樣的選擇是可能/建議在SQL查詢。我可以在應用程序端進行過濾,但顯然這意味着從數據庫中抽取無用的資源,所以如果可能的話(在數據庫方面便宜),我寧願將這項工作卸載到數據庫。

回答

2
select t.* 
from MyTable t 
inner join (
    select PartKey1, PartKey2, max(Version) as MaxVersion 
    from MyTable 
    where Version <= 2 
    group by PartKey1, PartKey2 
) tm on t.PartKey1 = tm.PartKey1 
    and t.PartKey2 = tm.PartKey2 
    and t.Version = tm.MaxVersion 
+0

爲什麼過濾條件在子查詢(CTE)的WHERE子句中? –

+0

@Jonathan:OP說:「在讀取數據時,我希望能夠指定最大版本。」* WHERE條款是一個如何去做的例子。 – RedFilter

+0

因爲確切的問題涉及指定版本號上限的功能。 (給出的例子是2)。 – MatBailie

5

你可以這樣做:

SELECT v1.* 
    FROM versioningscheme v1 
    LEFT JOIN versioningscheme v2 
    ON v2.partkey1 = v1.partkey1 AND v2.partkey2 = v1.partkey2 
    AND v2.version > v1.version 
WHERE v2.version IS NULL 

左與空探測加入是非常強大和充分利用。當不存在匹配時返回空值(很明顯,當您有v1中的最大行時,無法在v2中獲得滿足連接條件的行)。

+1

我強烈建議測試這個。我現在沒有oracle訪問權限,但我希望這種自加入類型的代價很高。 – MatBailie

+0

@Dems:實際上,Oracle優化器足夠智能,可以非常高效地完成此任務。重寫查詢以使用這種左連接,即使是在大型表格上,也顯示出將性能提升數倍。 – Benoit

+1

這與'WHERE NOT EXISTS(SELECT * FROM WHERE KEY =鍵和版本)版本'比較'?兩者都可以滿足反半連接。仍然會將這種反半連接方法與GROUP BY和ROW_NUMBER()替代方法進行比較,並探討代表性示例數據集上的行爲。 – MatBailie

2

這是常見的隨時間變化的數據(你選擇在特定的時間窗口內找到最近的值),並且是完全合理的。

在你的情況,ROW_NUMBER()允許數據只被解析一次,而不是多次。使用適當的INDEX,如(PartKey1, PartKey2, Version),這應該是特別快...

SELECT 
    * 
FROM 
(
    SELECT 
    *, 
    ROW_NUMBER() OVER (PARTITION BY PartKey1, PartKey2 ORDER BY Version DESC) AS reversed_version 
    FROM 
    MyTable 
    WHERE 
    Version <= <MaxVersionParamter> 
) 
    AS data 
WHERE 
    reversed_version = 1 
+0

我必須承認,我不明白所有的查詢'ROW_NUMBER()OVER(PARTITION BY PartKey1,PartKey2 ORDER BY Version DESC)AS reversed_version'對我來說是未知的! –

+0

'ROW_NUMBER()OVER(ORDER BY Version DESC)'只是按降序排列,按版本排序創建一組序號。通過PartKey1,PartKey2添加PARTITION指定您可以爲PartKey1,PartKey2的每個唯一組合獲得單獨的序列號。還有其他的窗口功能,比如常用的RANK()和DENSE_RANK()。與適當的索引匹配時,所有這些特別快速。當與DESCending命令和WHERE子句一起使用時,您可以確定oyu're感興趣的記錄始終是ROW_NUMBER()= 1。 – MatBailie

+0

這似乎相當有效,因爲OrderBy自然強加排序,它看起來像你不會執行任何無關的工作。你知道它是否與暴露的各種JOIN查詢相比有優勢? –