开篇介绍
在比较大的 ETL 项目中,父子包的使用频率非常的高。包括在一些自定义的 ETL 包调度框架中,父子包的使用构成了这些框架的基础。在 ETL 项目中使用父子包主要处于以下几点考虑:
- ETL 项目的并行开发 - 可以多人同时开发 ETL 子模块,最后统一集成到父包中。
- 业务模块的划分 - 不同的业务模块需要拆分到各个子包,最后组装起来,避免单个包业务逻辑过于复杂,模块划分不清的问题。
- 避免整个包失败的问题 - 避免因一个 Task 或者模块失败而导致整个包失败,在有的业务中是允许部分模块失败而其它模块可以继续执行的。
- 并行执行提高效率 - 多个子包并行执行,最大可能的利用服务器上的资源,提高整个 ETL 的执行效率。
- 共同参数,配置信息的控制 - 业务模块交叉的一些参数,配置都可以放在父包中完成,包括验证等。避免多个包中重复的参数配置,参数验证。
案例的设计
下面的案例通过一个父包,两个子包来演示父子包的调用过程并且演示子包引用父包参数的过程。
设计一张表对象,这是我们的目标表。
IF OBJECT_ID('T014_PROCESS_LOG') IS NOT NULL
DROP TABLE T014_PROCESS_LOG
GO
CREATE TABLE T014_PROCESS_LOG
(
EXECUTION_ID NVARCHAR(255),
PARENT_EXECUTION_ID NVARCHAR(255),
PACKAGE_NAME NVARCHAR(255),
MACHINE_NAME NVARCHAR(255),
START_TIME DATETIME NULL,
FINISH_TIME DATETIME NULL,
EXECUTE_STATUS_ID INT
)
SELECT * FROM T014_PROCESS_LOG
父包的创建
创建一个父包,并创建一个 Execute SQL Task,SQL Statement -
INSERT INTO T014_PROCESS_LOG VALUES(?,?,?,?,GETDATE(),NULL,1)
由于父包是没有父级 Execution 的,因此 EXECUTION_ID 和 PARENT_EXECUTION_ID 是相同的。
新建一个变量 PV_EXECUTION_ID,这个变量是通过一个表达式计算而来的。
拖放如下变量到表达式 Expression 中,这样在包执行过程中,变量 PV_EXECUTION_ID 的值将等同于系统变量 System::ExecutionInstanceGUID。
子包的创建与参数传递
创建一个新的Package,并新建一个变量 PP_EXECUTION_ID,这个变量将会接受来自于父包的 Execution ID。
回到包中,右键查看 Package Configurations 选项。如果没有这个选项(2012之前直接显示,2012需要先在属性中使用,之后会出现在左侧右键出现的位置),那么应该在包的属性中查找 Configurations,点击进入。
启用包配置并添加。
Configuration Type 选择 Parent package variable,Parent Variable 填入父包中的变量名称 PV_EXECUTION_ID。
下一步选择子包中的变量,选择它的Value 属性,那么这一步的作用就是将父包中 PV_EXECUTION_ID 的值传递给子包中的变量 PP_EXECUTION_ID。
为这个配置取一个名字 - PARANET_CONFIG,可以在下面看到具体的变量信息。
在子包中新建一个 Execution SQL Task,其连接方式和父包一样,SQL 语句一样,Data Mapping 中使用的是 PP_EXECUTION_ID,它将接受来自父包 PV_EXECUTION_ID 的值。
保存这个子包,并且按照同样的方式创建另外一个子包,包括上述的配置。
父子包的关联
在父包中 Execute SQL Task 之后拖放一个 Sequence Container,并在 Sequence Container 中拖放两个 Execute Package Task,每一个 Task 将绑定一个子包文件。
按照下方完成配置,如果 Connection 没有选项的时候,是需要新建一个文件连接,这个文件连接指向包文件。
文件连接管理器连接到子包文件,两个子包通过这种方式连接到了父包当中。
执行父包,在 Sequence Container 中两个子包都会被并行执行。
可以看到一次写入三条记录,第一条是父包写入的,第二条和第三条分别是两个子包写入的,但是他们的 PARENT_EXECUTION_ID 都是同一个,说明他们是来自于同一个父包的某一次执行。