2012-12-07 34 views
2

我有一個包含歷史數據的多個表,所以ID之間不是1對1的關係。含歷史數據加入多個表

我必須參加的ID和表示當數據一直活躍,TO_TIMESTMP可如果數據仍然是活動的,或者如果它從來沒有被定爲舊數據是空的時間戳。

我的一些分組後,主表輸出是這樣的:

TABLE_A 
AID USER_ID AMOUNT FROM_TIMESTMP  TO_TIMESTMP   
1  1   2  11/21/2012 00:00:00 12/04/2012 11:59:00 
1  2   3  11/24/2012 12:00:00 null     
2  1   2  11/21/2012 01:00:00 null     

然後我有使用鏈路還

TABLE_B 
AID CID FROM_TIMESTMP  TO_TIMESTMP   HIST_ID 
1  3  11/01/2012 00:00:00 null     1 
1  3  11/21/2012 00:00:00 12/04/2012 11:59:00 2 
1  3  11/24/2012 12:00:00 null     3 
2  4  11/21/2012 00:59:59 null     4 

和我的第三臺看起來是這樣的另一個表:

TABLE_C 
CID VALUE FROM_TIMESTMP  TO_TIMESTMP   HIST_ID 
3  A  11/01/2012 00:00:00 null     1 
3  B  11/21/2012 00:00:00 11/24/2012 11:59:00 2 
3  C  11/24/2012 12:00:00 null     3 
4  D  11/21/2012 01:00:01 null     4 

如果我想結合表A和來自表的值,我的預期輸出C到B表是:

AID USER_ID AMOUNT FROM_TIMESTMP  TO_TIMESTMP   VALUE 
1  1  2  11/21/2012 00:00:00 12/04/2012 11:59:00 B 
1  2  3  11/24/2012 12:00:00 null     C 
2  1  2  11/21/2012 01:00:00 null     D 

有除上表A數量和價值表C一切指標和我用下面的SQL拉出數據。

SELECT a.AID, a.USER_ID, a.AMOUNT, a.FROM_TIMESTMP, a.TO_TIMESTMP, c.VALUE from 
(SELECT AID, USER_ID, SUM(AMOUNT), FROM_TIMESTMP, TO_TIMESTMP from TABLE_A GROUP BY AID, USER_ID, FROM_TIMESTMP, TO_TIMESTMP) a 
inner join TABLE_B b on b.HIST_ID in (select max(HIST_ID) from TABLE_B 
where AID = a.AID and FROM_TIMESTMP <= a.FROM_TIMESTMP+1/2880 and (TO_TIMESTMP>= a.FROM_TIMESTMP or TO_TIMESTMP is null)) 
inner join TABLE_C c on c.HIST_ID in (select max(HIST_ID) from TABLE_C 
where CID = b.CID and FROM_TIMESTMP <= a.FROM_TIMESTMP+1/2880 and (TO_TIMESTMP>= a.FROM_TIMESTMP or TO_TIMESTMP is null)); 

由於保存數據時比較的情況下,開始時間標記,他們在那裏大約在同一時間創建的時候我加入了一個30秒的寬限期一些不一致的地方,有沒有改善我的方式做的方式這個?

我選擇了帶有MAX(HIST_ID)的一個,因此TABLE_A中的AID = 1和USER_ID = 2等情況只會得到與其他表中匹配的id/timestamp的最新行。

在我真實的數據我內連接4臺這樣的(而不是僅僅2)和它的作品在我的本地測試數據良好(要求所有的數據時,在11秒拉剛剛超過42000線)。

但是,當我嘗試在數據量更接近生產的測試環境中運行它時,即使通過設置FROM_TIMESTMP必須將第一個表中查詢的行數限制爲6000行時,運行速度也會減慢在兩個日期之間。

是否存在被做另一種方式來提高我的表的連接性能的方法是什麼?

+0

Oracle版本是我的本地機器「Oracle數據庫10g快捷版發佈10.2.0.1.0 - 產品」上,並 在測試環境中,「Oracle數據庫11g第二版11.2.0.3.0 - 64位生產「 – Blem

回答

2

一個簡單的改變,以避免MAX()重複子查詢的是:

select a.aid,a.user_id,a.amount,a.from_timestmp,a.to_timestmp,a.value 
    from (select a.aid,a.user_id,a.amount,a.from_timestmp,a.to_timestmp,c.value, 
     row_number() over (partition by a.aid,a.user_id order by b.hist_id desc, c.hist_id desc) rn 
    from (select aid,user_id,sum(amount) amount,from_timestmp,to_timestmp 
      from table_a 
     group by aid,user_id,from_timestmp,to_timestmp) a 
     inner join table_b b 
       on b.aid = a.aid 
       and b.from_timestmp <= a.from_timestmp + (1/2880) 
       and (b.to_timestmp >= a.from_timestmp or b.to_timestmp is null) 
     inner join table_c c 
       on c.cid = b.cid 
       and c.from_timestmp <= a.from_timestmp + (1/2880) 
       and (c.to_timestmp >= a.from_timestmp or c.to_timestmp is null)) a 
where rn = 1 
    order by a.aid, a.user_id; 
+0

花了一段時間來改變我的完整的SQL調用,但它看起來promesing。 它在我的本地計算機上運行速度稍慢,但要求在測試環境下解釋計劃時的成本從18.446.744.073.709.551.615減少到631.385(當不限制初始呼叫日期),因此它看起來很有前景 – Blem

1

有可能是爲什麼你的查詢運行在另一個上的一個環境和更快的速度較慢的原因有很多。最可能的原因是優化器定義了兩個不同的計劃,而且運行速度更快。可能因爲統計數據略有不同。

你當然可以優化您的查詢使用的索引,但我認爲你的主要問題在於數據和/或數據模型。如果數據不好,你會一次又一次地遇到這些問題。

這是很常見的數據歸檔到相同的表,它可以是有用的,表示需要進行查詢的歷史瞬態數據。但是,存檔數據不應該讓您忘記數據庫設計的基本規則。

就你的情況而言,你似乎有三個相關的表格:它們將會鏈接到你的實體關係模型中。然而,在設計過程的某個地方,他們丟失了這個鏈接,所以現在你無法可靠地確定哪一行依賴哪一個。

我建議如下:

  • 如果兩個表是在你的ER模型相關,添加一個外鍵。這將確保你可以隨時加入他們,如果你需要。外鍵僅在DML操作中增加了一小筆費用(並且只有INSERT,DELETE和更新到主鍵(?!))。如果你的數據被插入一次並被多次查詢,性能影響可以忽略不計。

    在你的情況,如果(AIDFROM_TIMESTAMP)是在你的TABLE_A主鍵,然後在TABLE_B參考TABLE_A的主鍵列相同的列。您可能需要FROM_TIMESTAMP_AFROM_TIMESTAMP_C,如果AC(這似乎不相關)具有不同的更新方案。

  • 如果你不遵循這個邏輯,你將不得不建立你的查詢。如果A,B和C每個歷史存檔但尚未完全引用,則只能通過單個時間點參考回答問題,如「時間TS時DB的狀態是什麼」:

    SELECT * 
        FROM A 
        JOIN B on A.aid = B.aid 
        JOIN C on C.cid = B.cid 
    WHERE a.timestamp_from <= :TS 
        AND nvl(a.timestamp_to, DATE '9999-12-31') > :TS 
        AND b.timestamp_from <= :TS 
        AND nvl(b.timestamp_to, DATE '9999-12-31') > :TS 
        AND c.timestamp_from <= :TS 
        AND nvl(c.timestamp_to, DATE '9999-12-31') > :TS 
    
+0

感謝您的意見,我認爲其中一個環境相對於另一個環境較慢的主要原因是數據量(如果要求在所有需要獲得的線路上進行計數,則本地數據中有42.000行,而本地數據中有19.000.000測試環境)。 這些表具有用於非歷史版本的外鍵,但不包含歷史數據,這裏它們只有HIST_ID的主鍵。 我是這個項目的新成員,並且不認爲現在是請求將外鍵添加到歷史數據中的最佳時機: 這就是爲什麼我要嘗試執行最後一項建議。 – Blem