微軟BI 之SSIS 系列 - Merge, Merge Join, Union All 合並組件的使用以及Sort 排序組件同步異步的問題


開篇介紹

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 博客推薦欄中快速看到這些文章。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM