開篇介紹
SSIS Data Flow 中有幾個組件可以實現不同數據源的數據合並功能,比如 Merger, Merge Join 和 Union All。它們的功能比較類似,同時也比較容易混淆,下面是對它們之間的區別的對比總結。
下面通過三個 Data Flow 來演示這三個組件的使用以及相關的配置。
測試數據源 -
第一個數據源是一張表
USE BIWORK_SSIS GO -- Merge demo table IF OBJECT_ID('DEMO_MG_Customer','U') IS NOT NULL DROP TABLE DEMO_MG_Customer GO CREATE TABLE DEMO_MG_Customer ( CustomerID INT PRIMARY KEY, CustomerCompany NVARCHAR(255), CustomerName NVARCHAR(20), CustomerAddress NVARCHAR(255) ) INSERT INTO DEMO_MG_Customer VALUES (1,'HFBZG','Allen,Michael','Obere Str. 0123'), (2,'MLTDN','Hassall, Mark','Avda. de la Constitución 5678'), (3,'KBUDE','Peoples, John','Mataderos 1000') SELECT * FROM DEMO_MG_Customer
第二個數據源是一個文本文件
ID,Company,CustomerName,Title,Address
1,'NRZBB','Allen,Michael','Sales Representative','Obere Str. 0123'
2,'MLTDN','Hassall, Mark','Owner','Avda. de la Constitución 5678'
3,'KBUDE','Peoples, John','Owner','Mataderos 7890'
4,'HFBZG','Arndt, Torsten','Sales Representative','7890 Hanover Sq.'
5,'HGVLZ','Higginbotham, Tom','Order Administrator','Berguvsvägen 5678'
示例一 - 使用 Merge 來合並數據
- 上面已經說了 Merge 的特點-
- 輸入數據源 - 兩個
- 輸入數據源 - 表或者文件等
- 合並時要求元數據相同,數據類型相同
- 合並前需要排序
合並操作類似於 SQL 語句中的 UNION ALL。
OLE_SRC_Customer - OLE DB Source 中指定的數據源來自 BIWORK_SSIS 數據庫中的 dbo.DEMO_MG_Customer 表。
表中的 5 個列都將作為輸出列向下輸出。
FF_SRC_Customer (Flat File Source) 的 Flat File Connection Manager 指向文本文件源。並且要注意 Text qualifier 是', 因為要注意到文本文件中位於 ' ' 之間的才是真正要處理的文本。
1,'NRZBB','Allen,Michael','Sales Representative','Obere Str. 0123'
並且指明文本文件中的第一行是列標題。
逗號分割列
在這里要注意的是文本文件中 ID 的數據類型指定 DT_I4 來映射 SQL Server 數據庫中的INT 類型,否則兩個數據源一旦有一個列數據類型不一致的話,那么合並操作時就會出現錯誤。
其它字符串用 DT_WSTR 即可,因為要和數據庫中的 NVARCHAR 數據類型匹配。
注意在 Flat File Source 向下輸出的時候並沒有選擇 Title, 因為這一列在 Input Table Source 中並不存在。在合並兩個來自不同數據源的時候,我們要求兩邊的元數據一致,即列的數量和類型也應該一致。
因為本身 ID 就是有序的,所以為了演示的效果選擇 CustomerName 作為排序列,兩邊的源的拍序列也應該選擇一致。
Merger Transformation 列出了輸出的列,兩個輸入源並且顯示了它們的排序列,最終輸出的結果也會按照 CustomerName 排序的結果來輸出。
Merge 之后來自於兩個不同數據源的數據就合並到了一起,並且 CustomerID = 2 的數據分別來自兩個數據源,內容也是一致的,但並沒有在合並的時候刪除重復的數據,這類似於 SQL 語句中的 UNION ALL 的操作,保留了重復項。
示例二 - 使用 Merge Join 組件合並數據
Merge Join 類似於 SQL 中的 Full/Left/Inner Join 等操作,因為不需要兩邊數據源的元數據一致。但是,它也要求左右兩邊的數據源排序,並且排序列必須包含后面使用到的 JOIN 列。
前面的配置和上一個例子中一樣,只是排序列改成了 CustomerID,只看 Merge Join 部分。
除了 Inner Join 外,還有 Full Join 和 Left Outer Join 等同於 SQL 中的 Inner Join/Full Join/Left Join 等操作。
看上面圖片中顯示了左右兩邊的數據源,其中 Join Key 必須包含在排序列中。在左邊的表數據源中有4個輸出列,與右邊文件中的 Title 輸出列共同組成了5個輸出列。
如果使用 SQL 語句來表示這里的邏輯,可以理解成-
SELECT tbl.CustomerID, tbl.CustomerCompany, tbl.CustomerName, tbl.CustomerAddress, ff.Title FROM ST_TBL_Customer AS tbl INNER JOIN ST_FF_Customer AS ff ON tbl.CustomerID = ff.ID
從這里看出 Inner Join 能關聯上3條數據,其中 Title 列來源於文件數據源。
在這里,也可以使用 Merge Join 組件完成對已存在的數據進行更新,對不存在的數據進行插入操作。比如可以使用 Left Outer Join, 假設以左表為目標表的話,那么就能夠利用關聯上 ID 的右文件數據源來更新左表,關聯不上的就作為新數據插入到左表中。只需要在 Merge Join 下加一個 Conditional Split 組件來判斷即可,可以參考我的另一篇文章 -
SSIS 系列 - Lookup 組件的使用與它的幾種緩存模式 - Full Cache, Partial Cache, NO Cache
示例三 - 使用 UNION ALL 組件合並數據
UNION ALL 組件與上面兩個組件最大的區別就是,一可以合並兩個以上的數據源,二是不需要對數據源進行排序。
這個示例中有三個數據源,前兩個和上面示例中的配置一樣,第三個數據源和第二個數據源實質上相同,都是指向同一個數據表。
直接看 UNION ALL 組件的配置,非常的簡單。
看到輸出列了嗎? 默認情況下將第一個文件數據源的列作為默認的整個組件的輸出列,如果后面的數據源沒有這些列的話,那么就忽略掉,其它的列再一一設置匹配一下,當然數據類型應該一致。
輸出的結果如下,有重復的數據並且也未排序。
三個組件各自不同的特點
簡單的可以歸納一下何時應該選擇 Merge, Merge Join 和 Union All 組件來合並不同數據源的數據呢?
- 如果有兩個以上的數據源 - UNION ALL
- 如果只有兩個數據源,並且是從兩個不同數據源基於一些關聯條件各取一部分數據 - Merge Join
- 如果只有兩個數據源,目的為了合並而非關聯 - UNION ALL/Merge
- 如果只有兩個數據源,目的只為了合並但不需要輸出的結果排序 - UNION ALL
- 如果只有兩個數據源,目的只為了合並但需要輸出的結果排序 - Merge
Asynchronous Transformation VS Synchronous Transformation
當然,除此之外還有些細節需要知道的是 - 盡量避免使用 Sort 排序組件,原因在於 Sort 排序組件被稱之為 Asynchronous Transformation。
Asynchronous Transformation 非同步轉換 - Blocked Transformation 阻塞轉換。Sort 排序組件就屬於這一類,和它相同的還有 Pivot 組件。
它們處理數據的過程是先從上游數據源中抽取所有數據,再開始處理排序,全部排序完成之后再產生輸出。這樣的過程極大的消耗了內存並且使得整個處理的過程變得緩慢。
相對於這類組件,有一類組件是屬於 Synchronous Transformation 同步轉換,比如:
- Derived Column
- Copy Column
- Data Conversion
這類組件基本上是從數據源一條一條的取,一條一條的處理並同時輸出給下游轉換組件。
所以在上面的幾個示例中,更優的選擇應該是在 OLE DB Source 的操作中使用 SELECT 語句加上排序操作來代替直接使用表或者視圖,這樣避免轉換阻塞。
因此對示例一做出一些修改,去掉中間的排序組件。
在 OLE_SRC_Customer 中使用 SELECT 語句加上排序操作使得輸出是已經排好序的結果。
SELECT CustomerID, CustomerCompany, CustomerName, CustomerAddress FROM dbo.DEMO_MG_Customer ORDER BY CustomerName
但是再次連接到 Merge 組件上時會發生錯誤,因為你還要通知一下 Merge 組件你是如何排序的。
右鍵 OLE_SRC_Customer 選擇 Advanced Editor,在 Input and Output Properties 這里修改一下 IsSorted 屬性,設置為 True, 默認是 False。 這樣就告訴了下游轉換組件,這里的結果是已經排好序的。
同時還需要指定如何排序,按照哪些列來排的序。因為在示例 Merge 中我們選擇的是 Customer Name, 因此這里將它的 0 修改為1。 0 表示是不排序的,1 表示是第 一個排序位,這里應該按照 ORDER BY 后面的列順序來設置,第二個排序列就設置為 2, 依此類推。
修改完畢后,再運行一下第一個示例,結果是一樣的
這里的數據量比較少,可以試一下10W級,100W級 以上使用 Sort 組件和不使用 Sort 組件的差別來體會一下這兩種處理方式的不同。
更多 BI 文章請參看 BI 系列隨筆列表 (SSIS, SSRS, SSAS, MDX, SQL Server) 如果覺得這篇文章看了對您有幫助,請幫助推薦,以方便他人在 BIWORK 博客推薦欄中快速看到這些文章。