SSIS学习使用八:高级SSIS工作流管理

1,097 阅读13分钟

这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

翻译参考

本文主要参考翻译自 The Stairway to Integration Services 系列文章的 Advanced SSIS Workflow Management – Level 8 of the Stairway to Integration Services,目的在于对 SSIS 有一个全面清晰的认识,所有内容在原文的基础上进行实操,由于版本差异、个人疑问等多种原因,未采用完全翻译的原则,同时也会对文中内容进行适当修改,希望最终可以更有利于学习和了解 SSIS,

感谢支持!

高级SSIS工作流管理

在之前的部分,我们创建了一个 新SSIS包,首先查看了脚本任务和SSIS中的优先约束。检查了 MaxConcurrentExecutables 包属性。还检查、演示和测试了优先约束的 “On Success”, “On Completion” 和 “On Failure” 功能。

本篇中,将深入了解 SSIS工作流管理 —— 学习 SSIS 变量和复杂的优先约束表达式。

关于变量(About Variables)

打开 Precedence.dtsx包(如果没打开的话)。点击 visual studio 顶部的 SSIS 下拉菜单,点击选中 "变量"(Variables) 菜单项,打开显示变量窗口。

在 变量窗口(Variables window) 的顶部,可以发现SSIS变量的工具条,这些按钮是:

  • 添加变量
  • 移动变量
  • 删除变量
  • 网格选项

在网格选项中,可以设置是否显示系统变量,以及变量窗口表格中显示的列。

系统变量是 System 命名空间下的变量。许多SSIS包属性、或SSIS包中创建的组件、对象属性都是系统变量。

变量和命名空间(Variables and Namespaces)

SSIS包中有两个默认命名空间:SystemUser。我们不能添加系统变量,但是可以添加 用户变量 或者 创建一个新命名空间。作用域和命名空间下的 变量名 必须是唯一的。

比如,在 "User" 命名空间中你可以有一个 "MyVariable" 变量名,完全限定名称是 "User::MyVariable"(<Namespace>::<VariableName>)。当前例子中,User::MyVariable 位于 Precedence.dtsx 包作用域中。我们可以在 "User2" 命名空间中有另一个变量 "MyVariable",User2::MyVariable 也是位于 Precedence.dtsx 包作用域。

为了创建 User2 命名空间,你需要显示命名空间列,并编辑"User"文本为"User2"。当在相同的作用域访问位于不同命名空间的相同名称变量时,你需要使用完全限定变量名,否则你将收到一个如下类似的错误:

变量名称不明确,因为具有该名称的多个变量存在于不同的命名空间中。指定名称空间限定名称以防止歧义。

The variable name is ambiguous because multiple variables with this name exist in different namespaces. Specify namespace-qualified name to prevent ambiguity.

添加变量(Add a Variable)

点击 变量窗口 的 "添加变量" 按钮,一个新的 Int32 数据类型的名为"变量"(Variable)的变量被创建。

重命名变量为"MyBool",修改它的数据类型为 Boolean。

现在,可以在优先约束表达式中使用该变量了。

表达式和优先约束

右击 “Script Task 1” 和 “Script Task 2” 之间的优先约束,点击 "编辑...",打开优先约束编辑器

这里有两组控制按钮,分别是 "约束选项"(Constraint options) 和 "多重约束"(Multiple constraints)。在构建SSIS包时,我将控制流任务定向为从上到下的顺序执行(top-to-bottom)。

位置任务(positioning tasks)的一个积极的副作用是执行流从上到下。优先约束编辑器上的 组框(groupboxes) 的排列与控制流上优先约束的物理布局在某种程度上保持一致:"约束选项"(Constraint options)组框 设置优先约束中与上一个任务或优先约束"起点"相关的属性;"多重约束"(Multiple constraints)组框 设置有关下一个任务或优先约束"端点"的属性。

在优先约束编辑器中,点击 "求值运算"(Evaluation operation) 下拉列表。可以看到几个选项列表:

  • 约束Constraint
  • 表达式Expression
  • 表达式和约束Expression and Constraint
  • 表达式或约束Expression or Constraint

默认选项是约束(之前的介绍都是使用的这个选项)。约束允许配置何时或是否执行下一个任务 —— 仅仅根据上一个任务的执行结果。值下拉列表包含约束评估的选项:成功,失败和完成。

优先约束中使用表达式

修改 "求值运算"(Evaluation operation) 下拉列表为 "表达式"(Expression),并在表达式文本框中输入"@MyBool"

点击 "测试"(test) 按钮,验证表达式文本框中的表达式。

SSIS 变量 MyBool 是一个 Boolean 类型的值,其默认值为False。表达式文本框中的值必须是 True 或 False。此处也可以编辑表达式为"@MyBool == True"。表达式"@MyBool"和"@MyBool == True"在逻辑上是相等的,因为它们有相同的结果。

配置好后,关闭优先约束编辑器。

调试运行 'Precedence.dtsx' 包。运行 "Script Task 1" 出现询问成功或失败的消息框。此时,无论你选择哪个选项都没关系,因为优先约束评估仅仅基于 SSIS 的 Boolean 变量@MyBool的值。@MyBool默认是 False,所以 "Script Task 2" 将永远不会执行(因为优先约束永远不能评估为True)

脚本任务的脚本中使用变量

下面创建更有用的测试。

打开 "Script Task 1" 编辑器,并点击 "ReadWriteVariables" 属性的省略号,显示选择变量窗口,选择 User::MyBool 变量。

点击确定按钮,关闭选择变量窗口,脚本任务编辑器的 ReadWriteVariables 属性现在包含了 SSIS 变量 "User::MyBool"。

点击"编辑脚本"(Edit Script)按钮,在 Main 函数中编辑代码如下:

public void Main()
{
        // TODO: Add your code here
        var sTaskName = Dts.Variables["TaskName"].Value.ToString();
        var boxRes = MessageBox.Show("设置MyBool为True?", sTaskName, MessageBoxButtons.YesNo);
        if (boxRes == DialogResult.Yes)
        {
            Dts.Variables["User::MyBool"].Value = true;
        }
        else
        {
            Dts.Variables["User::MyBool"].Value = false;
        }
        Dts.TaskResult = (int)ScriptResults.Success;
}

保存并关闭脚本编辑器,点击"确定"关闭脚本任务编辑器。

调试运行 Precedence.dtsx 包,分别测试点击 "Script Task 1" 中消息框的不同按钮:点"是"时会执行"Script Task 2";点"否"时,整个执行将在不执行"Script Task 2"情况下结束。

深入使用变量

右击 "Script Task 2",点击复制,然后右击控制流的空白部分,点击"粘贴"。将会出现 "Script Task 2 1" 脚本任务。

重命名 "Script Task 2 1" 为 "Script Task 3",从 "Script Task 1" 连接一个新的"优先约束"。

如果此时执行SSIS包,不管你点击设置的 MyBool 变量,"Script Task 1"都会执行成功,连接 "Script Task 1" 和 "Script Task 3" 的优先约束将会评估为True,消息框 "Script Task 3 completed" 将会显示。

右击 "Script Task 1" 和 "Script Task 3" 之间的有限约束,打开优先约束编辑器,改变 "求值操作"(Evaluation Operation) 为 “表达式”。在表达式文本框中输入 "!@MyBool",如下:

"!@MyBool" 表示 "Not MyBool"。点击确定按钮关闭编辑器。目前控制流应该和下面的相似

执行SSIS包,如果你点击 "Script Task 1" 提示框的"是"按钮,"Script Task 2" 将会执行;如果你点击"否"按钮,"Script Task 3" 将会执行

原文中有关于优先约束颜色的视觉反馈的介绍。实际上,在 Visual Studio 2010 shell(SQL Server 2012) 中,视觉反馈并没有起到足够的作用,因为其颜色并没有在相应状态下改变。可能和版本不同,此处省略此段内容。

复制并禁用以保留现有工作

在进行更多操作之前,让我们保留已经完成的工作。

从SSIS工具箱(toolbox)中,拖拽 “序列容器”(Sequence Container) 到控制流中。

SSIS工具箱的显示,可以通过顶部菜单 SSIS 中的菜单项 "SSIS工具箱" 控制

点击 控制流 的空白处,并围绕着三个脚本任务(script task)画一个盒子,可以将它们作为一组,整体拖拽到序列容器中

拖进入后,大多数时候,序列容器会自动调整大小围绕这些项。如果没有,可以手动调整大小。

右键 序列容器,点击 "复制"。然后,右击控制流的空白处,点击"粘贴"。此时控制流应该如下所示:

右击第一个序列容器(原始的那个),点击 "禁用"(Disable),序列容器和它的内容显示为禁用(变灰)

现在,当进行新工作时,我们可以保留已经完成的工作。

多重约束(Multiple Constraints)

在 "序列容器1" 中,删除 "Script Task 1"。同时也会删除 "Script Task 1" 与 "Script Task 2"/"Script Task 3" 之间的优先约束。复制 "Script Task 2" 并粘贴到 "序列容器1",重命名新脚本任务为"Script Task 4"。

移动和调整 "Script Task 2" 和 "Script Task 4"并排显示,"Script Task 2" 和 "Script Task 3"、"Script Task 4" 和 "Script Task 3"之间各自连接一个优先约束

现在,先考虑一下:为了使 "Script Task 3" 执行,必须做什么?

  1. 什么都不做。其他任务执行时,"Script Task 3" 也执行。
  2. "Script Task 3" 在 "Script Task 4" 或 "Script Task 2" 执行并成功之后执行。
  3. "Script Task 3" 在 "Script Task 4" 和 "Script Task 2" 执行并成功之后执行。
  4. "Script Task 3" 永远不执行。

可以通过检查两个 优先级约束编辑器 来找到答案,焦点放在 “多重约束” 组框上:

记住,多重约束框组 定义优先约束如何在端点(EndPoint,优先约束结束的箭头)工作。当端点上只有一个优先约束落在任务上是,这些选项没有意义(它们的行为方式相同)。但是,当有多个约束落在端点任务上时(如此处所示),这些选项至关重要。

"逻辑与"(Logical AND) 选项是默认选中的。意味着端点任务执行前,位于该端点任务上的所有优先约束必须评估。在此例中,它意味着 "Script Task 4" 和 "Script Task 2" 必须结束和成功,"Script Task 3" 才会触发。执行SSIS包进行验证。

直到 "Script Task 4" 和 "Script Task 2" 完成执行并成功,"Script Task 3" 才会开始执行(上面第3个答案)。这是逻辑与多重约束的作用。

下面测试 "逻辑或"(Logical Or)。停止调试运行,双击启用的优先约束中的一个打开编辑器,将多重约束更改为"逻辑或"。点击“确定”,关闭优先约束编辑器。连接"Script Task 3"的两个优先约束都变成了虚线表示。

由于多重约束处理的是端点任务(endpoint tasks)。对一个的改变将应用到所有连接到端点任务的优先约束。

之前,多重约束配置为"逻辑与",前面的优先约束必须都在执行后续任务之前进行评估。

现在配置为"逻辑或","Script Task 3" 执行前会做什么?此处是上面的答案2:"Script Task 3" 在 "Script Task 4" 或 "Script Task 2" 执行并成功之后执行。

执行SSIS包并进行测试。

混合约束和表达式评估操作(表达式求值运算)

如果 SSIS 仍在运行则停止它。

双击 "Script Task 4" 和" Script Task 3" 之间的优先约束打开优先约束编辑器。修改多重约束为逻辑与。设置 求值运算(Evaluation Operation) 为 "表达式和约束"(Expression and Constraint)。确认"值"设置为"成功",表达式设置为 "@MyBool"

为了这个优先约束进行评估(运算),前面的任务必须执行成功,并且 SSIS 变量 "User::MyBool" 的值必须为 True。"MyBool"默认设置为False。

这个优先约束将永不会评估为True,因为必须是约束为True(执行成功,Success)和表达式(MyBool)为True。但是MyBool是False。这样最后不管脚本任务是否执行成功,都会阻止优先约束的评估。

尝试执行当前包,可以发现 "Script Task 3" 将永远不会执行。

重新打开 "Script Task 4" 和 "Script Task 3" 之间优先约束编辑器。修改"求值运算"为"表达式或约束"(Expression or Constraint):

关闭编辑器,并运行SSIS包。这次"Script Task 3"将会执行。

"Script Task 3" 执行是因为连接到它的两个优先级约束都评估为True。很容易理解如何评估 "Script Task 2" 和 "Script Task 3" 之间的优先级约束。但是,"Script Task 4" 和 "Script Task 3" 之间的优先级约束如何评估?评估运算设置为“表达式或约束”,这意味着表达式或约束必须评估为True。如果两个都为True,则优先约束也将为True。但是OR条件至少需要一个表达式或约束条件来评估True。因为变量值设置为False,所以表达式 MyBool 的结果不为True。约束 —— 成功执行上一个任务 —— 评估为True。这就是允许执行 "Script Task 3" 的原因。

优先约束注释(Annotation)

在操作的过程中,你可能注意到:我们将"求值运算"从"表达式和约束"修改为"表达式或约束"的过程中,控制流中图画呈现在视觉上没有任何变化。(实际上,"求值运算" 只有修改 "约束" 的值时,才会在视觉上改变颜色)。

我们如何分辨其中的不同呢?可以借助于注释实现:点击优先约束选中它,然后按"F4"显示属性,可以看到第一个属性 "ShowAnnotation",将其设置为 "ConstraintOptions"。

ShowAnnotation 属性的 ConstraintOptions 设置显示:用于阐明优先级约束的评估操作(求值运算)的文本。

综合使用

编辑 "Script Task 2" 和 "Script Task 4" 的 Main() 函数代码如下:

public void Main()
{
         // TODO: Add your code here
         var sTaskName = Dts.Variables["TaskName"].Value.ToString();
         var boxRes = MessageBox.Show("set "+sTaskName + " Succeed?", "确认", MessageBoxButtons.YesNo);
         if (boxRes == DialogResult.Yes)
         {
             Dts.TaskResult = (int)ScriptResults.Success;
         }
         else
         {
             Dts.TaskResult = (int)ScriptResults.Failure;
         }
}

该代码在每个脚本任务中创建任务成功(success)的提示框。编辑 "Script Task 4" 和 "Script Task 3" 之间的优先约束,设置求值运算为 "表达式和约束"(Expression and Constraint),值为"失败",表达式为 "@MyBool"

编辑 "Script Task 2" 和 "Script Task 3" 之间的优先约束,设置求值运算为"表达式"(Expression),表达式为"!@MyBool"

如下,是两个优先约束的 "ShowAnnotation" 属性都为 "ConstraintOptions" 显示的效果:

求值运算(Evaluation Operation)设置为表达式,会导致 "ConstraintOptions" 显示为 "Completion and "。

"Script Task 3"执行之前会发生什么?

  1. 什么都不发生。当其他任务执行时,"Script Task 3"将执行。
  2. "Script Task 4" 或 "Script Task 2" 执行并成功后,将执行"Script Task 3"。
  3. "Script Task 4" 和 "Script Task 2" 执行并成功后,将执行"Script Task 3"。
  4. "Script Task 3" 将永远不会执行。

可以运行SSIS包测试下。

这是一个技巧问题(trick question,诡计问题)。答案是4 —— "Script Task 3" 将永远不会执行。

下面修改 "MyBool" 值为 True,"Script Task 2" 和 "Script Task 3" 之间的表达式改为 "@MyBool"

其他"陷阱"(Gotcha)

禁用 "Script Task 4",当执行SSIS包时,"Script Task 4" 将不执行,"Script Task 3" 也同样不会执行

为什么?MyBool为True,"Script Task 2"完成。"Script Task 4"跳过。当 "Script Task 4" 禁用后,控制流推断为 "成功"(Success)。这意味着"失败优先约束"将不会评估。

总结

本篇中,我们使用SSIS变量控制优先约束评估、检测多重约束,并查看了一个"陷阱(gotchas)"注意项。