微軟BI 之SSIS 系列 - Lookup 組件的使用與它的幾種緩存模式 - Full Cache, Partial Cache, NO Cache


開篇介紹

先簡單的演示一下使用 Lookup 組件實現一個簡單示例 - 從數據源表 A 中導出數據到目標數據表 B,如果 A 數據在 B 中不存在就插入新數據到B,如果存在就更新B 和 A 表數據保持統一。

隨后再來解釋在這個過程中使用到的一些術語,以及分析一下 Lookup 中出現的幾種緩存模式,各自的特點以及常用的場合。

案例講解

兩張表,一張是目標表 DEMO_LK_Customer,一張是 DEMO_LK_LegacyCustomer  舊系統表。我們可以理解我們這個示例要實現的目標是 DEMO_LK_Customer 表的數據要和DEMO_LK_LegacyCustomer 實現同步,保持一致。

USE BIWORK_SSIS
GO

-- Look up demo table
IF OBJECT_ID('DEMO_LK_Customer','U') IS NOT NULL
DROP TABLE DEMO_LK_Customer 
GO

IF OBJECT_ID('DEMO_LK_LegacyCustomer','U') IS NOT NULL
DROP TABLE DEMO_LK_LegacyCustomer 
GO

CREATE TABLE DEMO_LK_Customer
(
    CustomerID INT PRIMARY KEY, 
    CustomerCompany NVARCHAR(255), 
    CustomerName NVARCHAR(20),
    CustomerAddress NVARCHAR(255)
)

CREATE TABLE DEMO_LK_LegacyCustomer
(
    CustomerID INT PRIMARY KEY, 
    CustomerCompany NVARCHAR(255), 
    ContactName NVARCHAR(20),
    ContactTitle NVARCHAR(50),
    CustomerAddress NVARCHAR(255)
)

INSERT INTO DEMO_LK_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')

INSERT INTO DEMO_LK_LegacyCustomer VALUES 
(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')

SELECT * FROM DEMO_LK_Customer
SELECT * FROM DEMO_LK_LegacyCustomer

--UPDATE DEMO_LK_Customer SET CustomerName = ?, CustomerCompany = ?, CustomerAddress = ? WHERE CustomerID = ?

--UPDATE DEMO_LK_Customer SET CustomerName = ? WHERE CustomerID = ?

--UPDATE DEMO_LK_Customer SET CustomerAddress = ? WHERE CustomerID = ?

在測試數據中,我們認為兩張表的 ID 都是不變的唯一的,第1條數據和第3條數據不一致,第4條和第5條數據在目標表中不存在。

先看一下實現這個例子的 SSIS Package 結構,最外面的是一個數據流 DF_Lookup。

在數據流中,數據源 OLE_SRC_LegacyCustomer 在這個例子中使用的是 SQL Server 數據庫表,但是這個數據源也可以是文本文件,Excel 或者其它數據庫的表或者查詢的結果集。

這個數據源相對於 Lookup 組件 LKP_Customer 來說是 Lookup 組件的輸入項。

LKP_Customer 之后有兩個分支 - 匹配和不匹配分支,做的事情就是匹配的數據做更新,不匹配的數據做插入動作。

輸入源 OLE_SRC_LegacyCustomer 的配置

輸入源中要向下輸出的列 - 相對於 Lookup 組件,它的輸出是 Lookup 的輸入。

LKP_Customer 的緩存模式選擇的是默認模式 - Full Cache 完全緩存,連接類型 OLE DB Connection 。

從上一個組件中輸出的列即這里的數據源 Input 要到下面展示的表或者視圖 DEMO_LK_Customer 中查找匹配項,下面的 DEMO_LK_Customer 在Lookup 組件中被稱為 - Reference Table/Set 引用表/引用集,前面默認的 Full Cache 緩存的就是這里的 Reference Table - DEMO_LK_Customer。

解釋一下這個關聯和配置的含義 -

左邊 Available Input Columns 來源於 Input 即數據源中輸出的列,這些列會作為 Lookup 組件繼續向下一個組件輸出的列。

Available Lookup Columns 來源於 Reference table 即在緩存中的數據,已選中的 CustomerID 也會作為 Lookup 組件繼續向下一個組件輸出的列。

中間的黑色實心線描述了查詢時的關聯規則,以左邊為驅動表到右邊緩存表中查找 CustomerID 一致的數據,找到了則匹配成功,找不到則不匹配。

設置了如果不匹配則輸出不匹配的選項,因此在 Lookup 組件之后能看到 Lookup Match Output 和 Lookup No Match Output 選項。

我們要把匹配的 CustomerID, 將 Input 作為源,將 Reference Table 作為目標表,將 CustomerID 匹配的其它列的數據更新到目標表中。

添加組件 OLE_Command 來更新 DEMO_LK_Customer 目標表,選擇的是 Lookup Match Output -

UPDATE DEMO_LK_Customer SET CustomerName = ?, CustomerCompany = ?, CustomerAddress = ? WHERE CustomerID = ?

設置參數,這里就能看到有兩個 CustomerID,一個是來源於 Input 的 CustomerID,一個則是上一個數據源中 OLE_SRC_LegacyCustomer 的 CustomerID,這里隨便制定哪一個 CustomerID 都可以。

添加一個新組件 OLE DB Destination 連接的是 Lookup NO Match Output,並設置 DEMO_LK_Customer 為目標表,表示如果不匹配則添加新數據。

輸入輸出的 Mapping 關系。

執行 Package,看到從數據源中向下輸出 5 條數據,其中有 3 條數據與 Reference Table 通過 CustomerID 匹配上,因此根據 CustomerID 將最新的從 Input 中輸出的信息更新到已存在的目標表中。另外兩條不匹配,則添加到目標表中。

注意這里提到的幾個表雖然有的是同一張表,但是它們的角色是不一樣的 -

  • OLE_SRC_LegacuCustomer 中的表 DEMO_LK_LegacyCustomer - 作為 Lookup 組件  LKP_Customer 中的輸入源,被稱為 Input Table。
  • LKP_Customer 中引用的表 DEMO_LK_Customer 在 Lookup 組件中被稱為 Reference Table。
  • OLE_CMD_UpdateCustomer 和 OLE_DST_InsertNewCustomer 中出現的表 DEMO_LK_Customer 是目標表。

對於一下最后源表和目標表的數據,保持了同步,前提就是 CustomerID 在兩張表中都能夠唯一確定一條數據。在數據倉庫的設計中,也會設計一個 Key 能夠唯一確定業務系統和數據倉庫中的一條數據,使它們能夠在邏輯上能夠關聯起來。

但是這里有一個問題,就是第2條數據沒有變化,但是也會執行一次 Update 操作,可以看上面的例子中,Update 操作顯示的是3條數據輸入了。如果數據量比較多的情況下,像這樣的 Update 是沒有必要的。

因此下面要對這個例子進行一個簡單的改造,假設只有 CustomerCompany 和 CustomerAddress 會不一致的情況下,可以如何處理來避免無謂的更新操作。

我的改造是在查找匹配之后,添加一個組件 Conditional Split - CS_CheckValues 對輸出列做一個判斷,只在 CustomerCompany 和 CustomerAddress 不一致的情況下做出更新。

並且在 Lookup 組件中做出修改,因為要比較 Input table 和 Reference table 的兩個列,因此選中右邊的幾個列。

檢查的規則有3個,當兩個列都不一致的時候,到某一個列不一致的時候,並且也應該按照這種順序來確保第一種規則應該最先檢查。

(_CustomerName != ContactName) && (CustomerAddress != _CustomerAddress) && (CustomerCompany != _CustomerCompany)

_CustomerCompany != CustomerCompany

CustomerAddress != _CustomerAddress

最后添加相應的組件按照不同的規則執行對應的更新語句 -

--UPDATE DEMO_LK_Customer SET CustomerName = ?, CustomerCompany = ?, CustomerAddress = ? WHERE CustomerID = ?

--UPDATE DEMO_LK_Customer SET CustomerName = ? WHERE CustomerID = ?

--UPDATE DEMO_LK_Customer SET CustomerAddress = ? WHERE CustomerID = ?

再次執行這個 Package 的時候就能看到更新的時候只有兩條數據更新了,這樣就避免了不必要的全部更新。

這個例子往小了說就是一個表到另外一個表根據那些列然后關聯查詢出一些列合並或者不合並輸出,往大了說可以想象一下更多的場景。比如數據源是一個或者一批文件,Excel,需要定期將文件或者Excel中的數據同步更新到一個數據表中。比如將業務系統中的表數據更新到數據倉庫中,更新一下數據倉庫中的一些維度屬性或者事實數據(事實數據一般很少更新),或者添加一些新的事實數據。所以,Lookup 的使用在 SSIS 中相當於大多數組件來說使用的頻率還是比較高的。雖然,它的某些功能實現完全可以用其它的組件或者邏輯來代替,甚至直接使用 SQL 語句。但是某些時候,我們還是還考慮使用 Lookup,因為 Lookup 里有一些緩存的設計,可以提高我們處理數據的效率,特別是在 SSIS Package 中反復使用到同一個 Reference 對象的時候。

了解 Lookup 的緩存模式

下面提到的緩存模式只適用於 OLE DB Connection Manager,  Cache connection manager 類似於 OLE DB Connection Manager 中的 Full Cache Mode。

Full Cache 完全緩存模式 

這是 Lookup 的默認選項,選擇這個模式后,在數據流 Data flow 真正執行之前就會將表中的數據或者對應查詢結果的數據一次性的從數據源中將數據緩存到內存中。

特點:

  • 數據流(SSIS)執行之前緩存全部結果集。
  • 消耗內存大,增加了數據流的啟動時間。
  • 在數據流啟動之后執行速度要快,數據不需要從數據源中再次讀取。
  • 數據源中的數據更新此時將不再影響到緩存中的數據。
  • 緩存中的數據可以被后面的組件重復使用。

什么時候該使用 Full Cache?

  • Lookup 數據集比較大的時候,一次加載到內存可以反復使用,而不需要反復的去查詢數據庫。
  • 數據庫服務器不在本地,為了減少查詢次數的情況下也要考慮使用 Full Cache

使用 Full Cache 模式時要注意的地方:

  • 數據全部緩存在內存中,如果內存不夠並不會將超出部分的數據緩存到磁盤上,而是直接報錯 - Run out of memory
  • 由於數據集緩存在內存中,所以在使用 Lookup 的時候不應該直接使用表對象,而應該通過寫 SELECT 語句來減少不必要的列輸出並且可以加上 WHERE 條件來限定一下數據集的大小,簡而言之緩存的數據應該只包含有用的數據。
  • 數據一旦緩存,那么在數據流執行過程中就不會再去檢測之前源數據是否發生改變或者更新等等,除非數據流重新啟動執行。

Partial Cache 部分緩存模式

部分緩存模式下,數據流開始時緩存還是空的。當時數據流開始執行后,當 Lookup 組件需要根據輸入行找匹配數據的時候,這時 Lookup 組件會先檢查一下緩存有沒有匹配的數據,如果沒有就查詢數據庫,如果在數據庫中查到匹配的數據行的時候就把這個數據行緩存起來,以便下次使用。

查詢的過程可以這樣理解,比如 Input Source 中有一個 ID1  Lookup 對象的 ID2 匹配,那么每次就是拿 ID1  Lookup 的緩存中查一下有沒有 ID2的值和ID1的值匹配,如果沒有的話就用 ID1的值作為一個參數到 ID2 所在的數據庫進行查詢,因為每次查詢的結構是一樣的,所以只通過傳參數的形式,某種程序上重用了查詢語句。

特點:

  • 數據流啟動之前,緩存為空,數據流啟動時間要比完全緩存的情況下要快。
  • Lookup 的時候會慢,因為總要檢查緩存,如果有的話就直接用,如果沒有的話就需要查詢數據庫,每次查詢都是一次開銷。如果數據量比較大的話,那么開銷就會非常大。
  • 可以在 Advanced Options 中設置最大緩存,一旦緩存中的實際數據大小超過這個最大值的話,就會自動清理那些較少使用的數據為新的數據騰出空間。

什么時候該使用部分緩存?

  • Lookup 緩存對象數據量較少的時候,不需要花時間等待全部緩存結束后再開始數據流的執行。

No Cache 無緩存模式

每次匹配查詢都會去數據庫查一次。這種緩存模式下,數據量不大並且內存比較緊張的情況下才會使用,當然它對內存的消耗也相對最小。

以上三種都是 OLE DB 的連接模式,從 SQL Server 2008 開始也支持了一種新的緩存模式 - 文件緩存模式。文件緩存是將 Reference table 中的數據存放到一個共享文件中可以供后面使用同一 Reference table 的 lookup 使用。它對內存的消耗很少,文件的數據直接存放在磁盤上,因此可以處理非常大的 Reference table 數據。

我個人覺得大多數情況下會選擇 OLE DB 下的 Full Cache, 因為一般的BI項目數據量比較大並且數據大多主要是分析歷史數據,所以對數據的實時性要求不高。同時,現在大多數服務器的環境也有條件讓我們一次性加載足夠多G的數據放到內存中緩存起來以重復使用。

更多 BI 文章請參看 BI 系列隨筆列表 (SSIS, SSRS, SSAS, MDX, SQL Server) 如果覺得這篇文章看了對您有幫助,請幫助推薦,以方便他人在 BIWORK 博客推薦欄中快速看到這些文章。 


免責聲明!

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



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