2010-07-21 12 views
2

我使用OLEDB源調用存儲過程以通過在存儲中的三個SELECT語句之間執行UNION來獲取一組標記爲IUD的行程序。更改存儲過程中的選擇順序會影響SSIS掛起問題

A是一個填充了每天晚上從遺留系統帶來的數據的表格。 B是我們系統的數據,我們希望不斷更新遺留系統的數據。

SET NOCOUNT ON; 

-- entries in A that dont exist in B need to be inserted into B 
SELECT 
    A.ID, 
    B.ID, 
    A.data1, 
    A.data2, 
    A.data3, 
    A.data4, 
    F1.ID as Fkey1, 
    F2.ID as Fkey2, 
    'I' as InsertUpdateDeactivateFlag 
FROM A 
LEFT JOIN B ON A.val = B.val 
LEFT JOIN F1 ON A.f1val = F1.val 
LEFT JOIN F2 ON A.f2val = F2.val 
WHERE B.ID is null 

UNION ALL 

-- entries in A that do exist in B that have different field values 
SELECT 
    A.ID, 
    B.ID, 
    A.data1, 
    A.data2, 
    A.data3, 
    A.data4, 
    F1.ID as Fkey1, 
    F2.ID as Fkey2, 
    'U' as InsertUpdateDeactivateFlag 
FROM A 
INNER JOIN B ON A.val = B.val 
LEFT JOIN F1 ON A.f1val = F1.val 
LEFT JOIN F2 ON A.f2val = F2.val 
WHERE 
    A.data1 <> B.data1 OR 
    A.data2 <> B.data2 OR 
    A.data3 <> B.data3 OR 
    A.data4 <> B.data4 OR 
    F1.ID <> B.Fkey1 OR 
    F2.ID <> B.Fkey2 

UNION ALL 

-- entries in B that dont exist in A should have Active set to 0 
SELECT 
    A.ID, 
    B.ID, 
    B.data1, 
    B.data2, 
    null as data3, -- dont need this value for deactivates 
    null as data4, -- dont need this value for deactivates 
    B.Fkey1, 
    B.Fkey2, 
    'D' as InsertUpdateDeactivateFlag 
FROM A 
RIGHT JOIN B ON A.val = B.val 
WHERE A.ID is null 

然後我做使用該標誌以引導行至三個OLEDB命令,對於每行(插入,更新,或失活)來執行存儲過程中的一個的條件劃分。這三個程序寫入表B.

如果只有幾十行通過我的SSIS包,它工作正常。但是,當我們消除表B並重新填充(幾十萬個插入)時,該包會掛起。它只是掛起,沒有錯誤信息,沒有失敗。 OLEDB源讀取除最後幾行外的所有行(大約需要700行,每次都是相同的數),通過剩餘的流饋送行,然後掛起。我的同事說,它實際上在75分鐘左右之後完成。

存儲過程在SSMS中完美運行,並且每次都會在幾秒鐘內返回整個結果集。從來沒有任何問題,除了在SSIS。

現在奇怪的部分是,如果我將第三個SELECT語句(停用)從最後的結果集合移到union的第一個結果集,一切正常,並且程序包在大約3分鐘內執行!咦?另外,如果我不對停用進行連接,只需從其中一個表中返回所有行,它也可以正常工作。爲什麼SSIS會關心這個連接,或者它會怎麼知道呢?我也嘗試在外部SELECT包裝UNIONs無濟於事。

我們已經檢查過SQL Server Profiler,查詢執行正常,沒有鎖等。據我瞭解,在開始將行放入管道之前,SSIS已經從OLEDB源中獲取所有數據。因此,寫入我在SQL Server上選擇的同一個表所產生的併發問題不應該是一個問題,因爲在包開始處理之前讀取已完成(請糾正我,如果這是錯誤的)。

就好像SSIS在UNIONs按照特定順序分析存儲過程時不正確。是這樣嗎?有沒有人遇到類似的情況?或者有人可以在這個過程中看到我應該在哪裏尋找問題?

在實際的存儲過程中,SELECT項中有CASE語句,WHERE子句項中的ISNULL()以及WHERE子句項和SELECT項中的其他UDF調用,以防萬一。

謝謝。

回答

0

由於SSIS可能會在接收到數據時開始處理行,我的猜測是無法處理其中一個停用行,因爲union中的其他語句之一已經獲取該行(或創建該行)。

您是否嘗試過訂購UNION中的行?請記住,如果沒有ORDER BY,更改語句的順序可能會更改行接收和處理的順序。

+0

這很有趣。我會試試看看會發生什麼。 – 2010-07-21 16:29:43

+0

拋出ORDER BY,無論順序(asc/desc)如何工作。添加ORDER BY會增加執行計劃的時間,也許最後一個SELECT會在插入開始之前完成。我將研究這種特定連接(停用)的含義以及爲什麼它可能在同時插入時掛起。 – 2010-07-22 11:34:56

1

我曾經遇到的一些問題是,存儲過程在SSMS內運行良好,並且在外面執行非常糟糕,這是由parameter sniffing造成的。

+0

此特定proc不採用任何參數。非常信息鏈接。 – 2010-07-21 16:29:05

0

聽起來像你看着我最推薦的一切。在這種情況下,我通常會責怪grelmins,建立一個解決方法(比如你先做第三個查詢),然後繼續。

您是否在75分鐘內檢查了系統中存在的鎖?這可能表示在SSIS試圖在後續任務中「跳躍前進」時數據是否仍在被拉取。

根據鍵和基數的不同,將第三個查詢更改爲「不存在」形式可能更有效 - 儘管這不能解釋當前行爲。 (那就是,右外連接讓我緊張 - 你可以嘗試它作爲一個左外連接,和其他人一樣。)

-- entries in B that dont exist in A should have Active set to 0 
SELECT 
    A.ID, 
    B.ID, 
    B.data1, 
    B.data2, 
    null as data3, -- dont need this value for deactivates 
    null as data4, -- dont need this value for deactivates 
    B.Fkey1, 
    B.Fkey2, 
    'D' as InsertUpdateDeactivateFlag 
FROM B 
WHERE NOT EXISTS (SELECT 1 FROM A WHERE val = B.val) 
+0

不幸的是,沒有檢測到鎖並使用表提示來拒絕鎖定/強制鎖定沒有效果。 – 2010-07-21 16:33:43

1

我將要做兩件事情:

(1)在屬性窗口爲您的OLE DB組件製作此SQL語句,將ValidateExternalMetadata設置爲False(長鏡頭,但嘗試它)。

(2)製作3個OLEDB組件源並使用SSIS聯合組件。我認爲SSIS希望你做到這一點,坦率地說,我通常使用組件,而不是試圖讓UNION在一個OLEDB組件源中工作。

+0

我會嘗試這個設置。如果我必須重寫過程和包,我可以走這條路,謝謝。 – 2010-07-21 16:35:49

+0

同意第二點! – 2010-07-21 17:00:21

0

你在做SSIS的重要工作嗎?

難道你不能在SSIS中並行和UNION數據?我知道你有UNION ALL,但是SQL Server並不是真正特別的。另外,爲什麼聯盟,如果你只是要再次分裂?

好像你可以只讓三個獨立的表值UDF和簡單:

INSERT INTO B 
SELECT * 
FROM udf_INSERTS() 

UPDATE B 
SET whatever 
FROM B 
INNER JOIN udf_UPDATES() AS u 
    ON u.key = B.key 

DELETE 
FROM B 
WHERE B.key IN (SELECT key FROM udf_DELETES()) 

所有直SQL。

在SSIS中調用單個插入/更新的SP並不是很快。因此,通常我喜歡流式傳輸到一個表,然後使用SQL語句來執行設置操作。

在你的情況中,SSIS做的很多工作都不是很清楚(樞軸,排序,聚集,查找,異構數據,腳本,驗證)(你在SSIS之外工作,然後分裂SSIS和調用單獨的SP來獲得結果的行),所以我只是把它扔到那裏。

相關問題