在SSIS的體系結(jié)構(gòu)中,Package是SSIS的最重要的部分,從本質(zhì)上來講,Package是一個(gè)有序地執(zhí)行任務(wù)的單元。Package的核心是控制流(Control Flow),用于協(xié)調(diào)包中所有組件的執(zhí)行順序。數(shù)據(jù)流(Data Flow)是控制流中的核心組件,用于把數(shù)據(jù)提取到服務(wù)器內(nèi)存中,轉(zhuǎn)換數(shù)據(jù)并把數(shù)據(jù)寫入到目標(biāo)結(jié)構(gòu)中。
一,控制流
控制流用于協(xié)調(diào)包中所有組件的執(zhí)行順序,這些組件由Task和容器構(gòu)成,并且受到優(yōu)先約束的控制。
控制流由三大組件構(gòu)成,分別是Task,容器和優(yōu)先約束。
容器用于把Task集合到一起,除了視覺上的分組外,容器還允許用戶定義作用域在容器范圍內(nèi)的變量和事件處理程序。
Task是一個(gè)獨(dú)立的工作單元,為包提供了實(shí)現(xiàn)特定功能的接口。
優(yōu)先約束不僅把Task連接到一起,而且指定Task執(zhí)行的順序。
Task按照優(yōu)先約束(Precedence Constraint)規(guī)定的順序執(zhí)行下去。在一個(gè)Task工作之前,Package必須完成其前面Task,不管前面的Task執(zhí)行的結(jié)果是成功、失敗或者完成。
1,優(yōu)先約束
優(yōu)先約束是把Task連接到一起的連接器,而且定義了Task的執(zhí)行順序。優(yōu)先約束定義了Task的執(zhí)行路徑和條件,只有滿足優(yōu)先約束的條件時(shí),才能按照連接路徑繼續(xù)執(zhí)行下一個(gè)Task。例如,在下圖所示的控制流中,優(yōu)先約束把Execute SQL Task和 Data Flow Task連接到一起,并且規(guī)定只有Execute SQL Task都執(zhí)行完成之后,才會(huì)執(zhí)行Data Flow Task。
為兩個(gè)Task創(chuàng)建優(yōu)先約束,必須設(shè)置約束值或表達(dá)式,當(dāng)約束值或表達(dá)式為True時(shí),滿足約束條件。
優(yōu)先約束的求值運(yùn)算(Evaluation operation)有四種:
約束(Constraint),根據(jù)約束的結(jié)果來確定約束的狀態(tài)
表達(dá)式(Expression),根據(jù)表達(dá)式的結(jié)果來確定約束的狀態(tài)
表達(dá)式和約束(Expression and Constraint),根據(jù)表達(dá)式和約束結(jié)果的組合來確定約束的狀態(tài)
表達(dá)式或約束(Expression or Constraint),根據(jù)表達(dá)式或約束的結(jié)果之一來確定約束的狀態(tài)
根據(jù)約束選項(xiàng)的不同,約束值有Value和表達(dá)式兩種類型:
當(dāng)求值選項(xiàng)為約束時(shí),約束值有:成功(Success)、失?。‵ailure)和完成(Completion);
當(dāng)求值選項(xiàng)為表達(dá)式時(shí),需要用戶編寫表達(dá)式;
約束值共有三種有效值,他們的含義是:
成功約束:表示只有在前置任務(wù)或容器成功時(shí),才會(huì)執(zhí)行當(dāng)前的任務(wù);
失敗約束:表示只有在前置任務(wù)或容器失敗時(shí),才會(huì)執(zhí)行當(dāng)前的任務(wù);
完成約束:表示只有在前置任務(wù)或容器完成(不管失敗或成功)時(shí),才會(huì)指定當(dāng)前的任務(wù)
當(dāng)一個(gè)Task上創(chuàng)建了多個(gè)約束時(shí),必須設(shè)置多個(gè)約束的邏輯組合。當(dāng)設(shè)置為邏輯與時(shí),多個(gè)優(yōu)先約束同時(shí)為True,才滿足優(yōu)先約束的條件;當(dāng)設(shè)置為邏輯或時(shí),只要有一個(gè)約束為True,就滿足優(yōu)先約束的條件。多重約束使當(dāng)前Task在前置任務(wù)都成功(邏輯與)的情況下,或者任意一個(gè)前置任務(wù)成功(邏輯或)的情況下執(zhí)行。
2,優(yōu)先約束控制Task的并發(fā)
控制流不能在Task組件之間傳遞數(shù)據(jù),它擔(dān)當(dāng)Task的調(diào)度者,用于串行或并行執(zhí)行任務(wù)。如果兩個(gè)Task之間沒有設(shè)置優(yōu)先約束,那么這兩個(gè)Task是并發(fā)執(zhí)行的。在設(shè)計(jì)Package時(shí),應(yīng)該最大限度地提高Task組件的并發(fā)處理能力,這樣能夠充分利用服務(wù)器的系統(tǒng)資源,有助于減少ETL執(zhí)行的時(shí)間。
3,Task組件通過優(yōu)先約束保持同步
在Task組件之間設(shè)置優(yōu)先約束,只有在上游Task執(zhí)行完成之后,才會(huì)執(zhí)行下游Task;在上游Task執(zhí)行完成之前,下游Task不會(huì)執(zhí)行。因此,Task是同步的。
Task的同步表現(xiàn)在兩個(gè)方面:
Task之間:一個(gè)Task在將操作移交之前必須完成(成功,失敗或完成),一個(gè)Task要想運(yùn)行,其所有上游Task必須全部完成,否則不會(huì)執(zhí)行。Task的執(zhí)行順序由優(yōu)先約束定義。
單個(gè)Task:Task在執(zhí)行完成之前,不會(huì)釋放SSIS的執(zhí)行線程,即執(zhí)行SSIS Task對(duì)服務(wù)器的線程資源是獨(dú)占的,直至Task 完成,否則不會(huì)釋放線程資源。
二,數(shù)據(jù)流
數(shù)據(jù)流(Data Flow)是控制流中的核心組件,用于把數(shù)據(jù)提取到服務(wù)器內(nèi)存中,轉(zhuǎn)換數(shù)據(jù)并把數(shù)據(jù)寫入到目標(biāo)結(jié)構(gòu)中。由于數(shù)據(jù)流任務(wù)把數(shù)據(jù)加載到服務(wù)器內(nèi)存中進(jìn)行轉(zhuǎn)換,因此,SSIS屬于內(nèi)存中的ETL工具,這使得SSIS可以高效地執(zhí)行數(shù)據(jù)的轉(zhuǎn)換操作。數(shù)據(jù)流的核心功能是把數(shù)據(jù)提取到服務(wù)器的內(nèi)存中,轉(zhuǎn)換數(shù)據(jù)之后,把數(shù)據(jù)寫入到另一個(gè)目的中。數(shù)據(jù)從源移動(dòng)到目的,使用的是內(nèi)存管道(Pipeline)。當(dāng)數(shù)據(jù)在管道中時(shí),你可以使用轉(zhuǎn)換組件對(duì)這些數(shù)據(jù)進(jìn)行清洗和處理。
數(shù)據(jù)流具有流的特性,數(shù)據(jù)的提取,轉(zhuǎn)換和加載是同時(shí)進(jìn)行的。SSIS引擎以流的形式對(duì)數(shù)據(jù)進(jìn)行并發(fā)處理,這意味著數(shù)據(jù)不是一次性全部加載,而是劃分為不重復(fù)的多個(gè)部分,組成一個(gè)流,源源不斷地從上游組件流向下游組件。在數(shù)據(jù)流動(dòng)的過程中,數(shù)據(jù)流的所有轉(zhuǎn)換組件同時(shí)對(duì)數(shù)據(jù)流進(jìn)行處理。上游組件處理完一批數(shù)據(jù)之后,交接給下游組件繼續(xù)處理,同時(shí),上游組件繼續(xù)處理下一批數(shù)據(jù)。數(shù)據(jù)在組件之間流動(dòng),各個(gè)組件同時(shí)處理數(shù)據(jù)的不同部分,直到全部數(shù)據(jù)處理完成。
數(shù)據(jù)流具有反饋和自動(dòng)調(diào)節(jié)的功能,如果下游組件的處理速度存在壓力,那么SSIS將會(huì)向上游組件施加反向壓力,SSIS引擎感受到壓力,將啟動(dòng)自動(dòng)調(diào)節(jié)機(jī)制,使上游組件的數(shù)據(jù)流動(dòng)速度減緩,從而達(dá)到動(dòng)態(tài)平衡。
數(shù)據(jù)流任務(wù)由四部分組成:源,轉(zhuǎn)換、目的和路徑,分別用于把數(shù)據(jù)加載到內(nèi)存中,對(duì)內(nèi)存中的數(shù)據(jù)進(jìn)行轉(zhuǎn)換,并內(nèi)存中的數(shù)據(jù)轉(zhuǎn)移到目標(biāo)中,數(shù)據(jù)按照路徑來“移動(dòng)”:
源:用于指定外部數(shù)據(jù)源位置,把外部數(shù)據(jù)加載到內(nèi)存中,向下游組件輸出數(shù)據(jù)。
轉(zhuǎn)換:轉(zhuǎn)換是在內(nèi)存中完成的,用于對(duì)管道中的數(shù)據(jù)進(jìn)行更改,影響內(nèi)存數(shù)據(jù)管道內(nèi)的數(shù)據(jù),是數(shù)據(jù)流的核心功能。
目的:在數(shù)據(jù)管道的終點(diǎn),數(shù)據(jù)離開數(shù)據(jù)管道,把數(shù)據(jù)輸出到外部存儲(chǔ)。
路徑:數(shù)據(jù)流組件之間的連線叫做路徑,數(shù)據(jù)按照路徑來轉(zhuǎn)移,可以視為數(shù)據(jù)走的路線。
外部數(shù)據(jù)源是數(shù)據(jù)管道的源泉,通常表示為連接(Connection),SSIS通過連接去訪問外部數(shù)據(jù)源,連接管理器用于設(shè)置連接的屬性,主要是用于用于集中設(shè)置訪問數(shù)據(jù)源的連接字符串,該連接管理器可以被多個(gè)組件共享,也可以被多個(gè)Package共享。
1,數(shù)據(jù)流的緩沖區(qū)
數(shù)據(jù)管道是數(shù)據(jù)流通的管道線,數(shù)據(jù)流使用內(nèi)存暫時(shí)存儲(chǔ)數(shù)據(jù)流中的數(shù)據(jù),這意味著,把數(shù)據(jù)從外部源提取到SSIS引擎時(shí),數(shù)據(jù)會(huì)存儲(chǔ)在預(yù)先分配好的內(nèi)存緩沖區(qū)中,可以根據(jù)數(shù)據(jù)行的寬度(一個(gè)row中所有column的字節(jié)數(shù)),設(shè)置DefaultBufferMaxRows屬性調(diào)整緩存區(qū)可以容納的最大數(shù)據(jù)行數(shù)量,或直接設(shè)置DefaultBufferSize屬性來調(diào)整緩沖區(qū)的大小。
數(shù)據(jù)流的緩沖區(qū)可以理解為一個(gè)二維表,每行有固定的長度,每一列的位置都是固定的。SSIS 引擎根據(jù)服務(wù)器的資源和壓力,預(yù)先分配一組緩沖區(qū),每一個(gè)緩沖區(qū)存儲(chǔ)完整數(shù)據(jù)集的一個(gè)不重復(fù)子集。當(dāng)對(duì)數(shù)據(jù)流進(jìn)行轉(zhuǎn)換處理時(shí),SSIS 引擎后臺(tái)使用一種更為有效的方式:對(duì)同一個(gè)緩沖區(qū),逐個(gè)應(yīng)用轉(zhuǎn)換組件,這比把轉(zhuǎn)換后的數(shù)據(jù)復(fù)制到另一個(gè)緩沖區(qū),然后應(yīng)用下一個(gè)轉(zhuǎn)換組件更為有效。不過,有些情況下,SSIS引擎需要復(fù)制緩沖區(qū),甚至需要攔截?cái)?shù)據(jù)流,然后對(duì)整個(gè)數(shù)據(jù)集進(jìn)行轉(zhuǎn)換處理,例如,聚合和排序。
SSIS 引擎處理數(shù)據(jù)最理想的情況是:所有的轉(zhuǎn)換施加在同一個(gè)緩沖區(qū)中,就地執(zhí)行轉(zhuǎn)換處理數(shù)據(jù)。但是,現(xiàn)實(shí)情況不總是理想的,有些轉(zhuǎn)換組件需要復(fù)制緩沖區(qū),才能向下游傳遞數(shù)據(jù)。
數(shù)據(jù)流通過轉(zhuǎn)換組件時(shí),SSIS 引擎是否需要復(fù)制緩沖區(qū),跟轉(zhuǎn)換的阻塞特性和通信機(jī)制有關(guān)。
2,轉(zhuǎn)換的阻塞特性:非阻塞(流),半阻塞和阻塞
非阻塞:立即把數(shù)據(jù)從管道中傳遞到下游的轉(zhuǎn)換
半阻塞:把數(shù)據(jù)增加到一定數(shù)量后再傳遞到下游的轉(zhuǎn)換
阻塞:在接收全部數(shù)據(jù)之后,再傳遞到下游的轉(zhuǎn)換
大多數(shù)轉(zhuǎn)換都是流式的,這意味著在轉(zhuǎn)換應(yīng)用到某一行時(shí),不會(huì)阻止數(shù)據(jù)移動(dòng)到下一個(gè)轉(zhuǎn)換。排序轉(zhuǎn)換和聚合轉(zhuǎn)換是阻塞的,這意味著每種轉(zhuǎn)換在向一個(gè)轉(zhuǎn)換傳遞數(shù)據(jù)之前,需要使用完整的數(shù)據(jù)集,在轉(zhuǎn)換結(jié)束之前,不會(huì)向下游組件釋放任何數(shù)據(jù)。通過在數(shù)據(jù)流鎮(zhèn)南關(guān)使用一個(gè)阻塞轉(zhuǎn)換組件,數(shù)據(jù)流將被攔截,所有行都將停留在阻塞轉(zhuǎn)換組件中,直到最后一行流進(jìn)轉(zhuǎn)換組件。
阻塞轉(zhuǎn)換是非常低效的和資源消耗大的,因?yàn)樗袛?shù)據(jù)都被攔截,所以server必須使用大量的內(nèi)存來存儲(chǔ)數(shù)據(jù),或者如果Server沒有足夠的內(nèi)存,那么Server會(huì)將部分?jǐn)?shù)據(jù)暫存在磁盤上,從而導(dǎo)致IO開銷;因?yàn)橐獙?duì)大量的數(shù)據(jù)進(jìn)行排序,聚合等操作,需要消耗大量的CPU資源和內(nèi)存資源。
3,轉(zhuǎn)換組件的通信機(jī)制
轉(zhuǎn)換組件的通信是指轉(zhuǎn)換組件把數(shù)據(jù)傳遞給下一個(gè)轉(zhuǎn)換組件,如果輸入所使用的緩沖區(qū)和輸出所使用的緩沖區(qū)不一樣,那么轉(zhuǎn)換的輸出就是異步的,換句話說,異步轉(zhuǎn)換組件不能夠既執(zhí)行指定操作又維護(hù)緩存區(qū)(行數(shù)或者行的順序),所以必須復(fù)制數(shù)據(jù),以實(shí)現(xiàn)所期望的結(jié)果。異步轉(zhuǎn)換組件接收上游組件的輸出緩沖區(qū),然后創(chuàng)建新的緩沖區(qū),輸出到下一個(gè)組件。
如果輸入所使用的緩沖區(qū)和輸出所使用的緩沖區(qū)相同,那么轉(zhuǎn)換的輸出是同步的,同步轉(zhuǎn)換組件不會(huì)創(chuàng)建新的緩沖區(qū),而是復(fù)用緩沖區(qū)。
緩沖區(qū)的生命周期,是從創(chuàng)建緩沖區(qū)開始,到異步轉(zhuǎn)換組件截止。由于異步轉(zhuǎn)換組件需要?jiǎng)?chuàng)建額外的緩沖區(qū),消耗Server的內(nèi)存資源,降低Server處理數(shù)據(jù)的性能,因此理想的Package Design是一個(gè)Data Flow 只使用一個(gè)緩沖區(qū)完成所有的轉(zhuǎn)換處理操作,所有的轉(zhuǎn)換都是同步輸出的。在實(shí)際的工作中,我們可以盡量不適用異步轉(zhuǎn)換組件,或是減少緩沖區(qū)創(chuàng)建的數(shù)量,盡量延長緩沖區(qū)的生命周期。
4,識(shí)別轉(zhuǎn)換的同步輸出和異步輸出
數(shù)據(jù)流的緩沖區(qū)可以看作是一個(gè)二維表,每行有固定的長度,每列的位置都是固定的,因此一列在同一個(gè)緩沖區(qū)中的標(biāo)識(shí)符是相同的。如果該列復(fù)制到新的緩沖區(qū)中,那么,該列的標(biāo)識(shí)符發(fā)生變化。SSIS Engine使用LineageID屬性來標(biāo)識(shí)緩沖區(qū)中的每一列。
在轉(zhuǎn)換組件的高級(jí)編輯器中,每列都有一個(gè)LineageID屬性,這是一個(gè)指向緩沖區(qū)的指針,標(biāo)識(shí)該列在緩沖區(qū)中的位置。
如果轉(zhuǎn)換輸出是同步的,那么同一列的LineageID屬性在轉(zhuǎn)換的輸出和輸入中是相同的,如果轉(zhuǎn)換輸出是異步的,那么同一列的LineageID屬性在轉(zhuǎn)換的輸出和輸入中是不同的。
例如,Column1 的初始LineageID值是193,如果轉(zhuǎn)換輸出是同步的,在轉(zhuǎn)換的Input和Output中,可以看到Column1的LineageID是193.
5,數(shù)據(jù)流緩沖區(qū)的申請(qǐng)和釋放
數(shù)據(jù)源組件會(huì)創(chuàng)建新的緩沖區(qū),并為相應(yīng)的數(shù)據(jù)列分配LineageID值。
當(dāng)緩沖區(qū)數(shù)據(jù)被加載到數(shù)據(jù)目的組件之后,數(shù)據(jù)目的組件會(huì)釋放緩沖區(qū)。
異步轉(zhuǎn)換組件會(huì)終止輸入緩沖區(qū),新建輸出緩沖區(qū)。
同步轉(zhuǎn)換組件復(fù)用輸入緩沖區(qū),并作為輸出緩沖區(qū),傳遞給下一個(gè)轉(zhuǎn)換組件。
三,異步轉(zhuǎn)換示例
異步轉(zhuǎn)換輸出是指:轉(zhuǎn)換的輸入緩沖區(qū)和輸出緩沖區(qū)不同,對(duì)于只包含OLE DB Source和Sort轉(zhuǎn)換的數(shù)據(jù)流任務(wù),在Sort轉(zhuǎn)換中,輸出列有LineageID屬性,當(dāng)數(shù)據(jù)列第一次被存儲(chǔ)到數(shù)據(jù)流中,SSIS引擎確定該列的LineageID,用于標(biāo)識(shí)數(shù)據(jù)流的緩存區(qū)的位置。
1,數(shù)據(jù)源組件
數(shù)據(jù)源組件含有外部列和輸出列,外部列直接來源于外部數(shù)據(jù)源,輸出列是數(shù)據(jù)源向下游輸出的數(shù)據(jù)。數(shù)據(jù)源組件創(chuàng)建緩沖區(qū),將外部數(shù)據(jù)加載到緩沖區(qū)中,并為緩存區(qū)分配LineageID,這個(gè)緩沖區(qū)就是數(shù)據(jù)源組件的輸出。
2,Sort 組件
Sort組件接收數(shù)據(jù)源組件的輸出數(shù)據(jù),對(duì)于Sort組件的輸入(Sort Input),ID 列的LineageID是197,這跟數(shù)據(jù)源的輸出的ID列的LineageID屬性相同,這說明,Sort 轉(zhuǎn)換直接使用數(shù)據(jù)源的輸出作為Sort轉(zhuǎn)換的輸入。
Sort 轉(zhuǎn)換的輸出(Sort Output),ID列的LineageID屬性值是 288,之所以存在不同的LineageID值,是因?yàn)镾ort轉(zhuǎn)換的輸出是異步的,輸入緩沖區(qū)和輸出緩沖區(qū)不同,因此,Sort轉(zhuǎn)換的輸出需要一個(gè)新的列標(biāo)識(shí)符。
SortColumnID屬性用于指定跟輸出列相關(guān)的輸入列的LineageID,輸出列ID的SortColumnID屬性值是197,是輸入列的LineageID。
所有具有半阻塞性和阻塞性的轉(zhuǎn)換都是異步輸出的,這些轉(zhuǎn)換不會(huì)直接向下游傳遞輸入緩沖區(qū),因?yàn)樾枰獢r截?cái)?shù)據(jù)以進(jìn)行處理和重組。
四,同步轉(zhuǎn)換示例
條件分離轉(zhuǎn)換(Conditional Split)是非阻塞組件,在數(shù)據(jù)流任務(wù)中,使用條件分離組件,把數(shù)據(jù)源組件的輸出按照特定的條件分開流向不同的目的。
1,Conditional Split組件
打開Conditional Split的編輯器,選中Case1,查看屬性SynchronousInPutID和IdentificationString:
IdentificationString:用于指定組件的數(shù)據(jù)流,其值具有特定格式的字符串,例如:?Conditional Split.Inputs[conditional Split input],
SynchronousInPutID:用于指定跟組件的輸出相關(guān)的行的輸入ID,其值是輸入的IdentificationString。
如果組件的屬性SynchronousInPutID為None,說明組件會(huì)創(chuàng)建新的輸出流,轉(zhuǎn)換輸出是異步的,如果組件的屬性SynchronousInPutID 是一個(gè)IdentificationString,說明組件的輸出和輸入使用相同的緩沖區(qū)。
選中 Conditional Split的輸入,查看屬性IdentificationString的值,和組件的輸出Case1的SynchronousInPutID屬性值相同。
2,驗(yàn)證LineageID值
查看Sort組件的Input Columns,ID列的LineageID是 197,和數(shù)據(jù)源組件的輸出,Conditional Split的輸入都相同,說明Conditional Split沒有創(chuàng)建新的數(shù)據(jù)緩沖區(qū),而是直接使用數(shù)據(jù)源創(chuàng)建的緩沖區(qū)進(jìn)行轉(zhuǎn)換。
結(jié)論:在同步轉(zhuǎn)換輸出中,當(dāng)完成了轉(zhuǎn)換邏輯之后,會(huì)立即將緩沖區(qū)傳遞到下游的轉(zhuǎn)換,即轉(zhuǎn)換輸入和轉(zhuǎn)換輸出使用相同的緩沖區(qū),避免復(fù)制緩沖區(qū)到輸出,因此相同列的LineageID是相同的。
用戶可以通過高級(jí)編輯器識(shí)別同步轉(zhuǎn)換組件和異步轉(zhuǎn)換組件,查看輸出的SynchronousInPutID屬性,如果SynchronousInPutID屬性值為None,那么該組件輸出是異步的,如果該值不是None,而是IdentificationString 格式的字符串,那么該轉(zhuǎn)換是同步的。
編輯:hfy
評(píng)論
查看更多