如何使用SSIS 2014在企业ETL环境中大规模管理包配置?

时间:2015-09-22 01:35:44

标签: sql-server ssis etl

我正在将一些软件包从SSIS迁移到2014年.MS正在鼓励转向项目部署并使用SSIS环境进行配置,因为它更灵活,但我根本没有发现这种情况。

在以前的版本中,当涉及到配置时,我使用了一系列技术。现在,如果我想使用项目部署,我只限于环境。

对于所有包通用的变量,我可以设置一个环境,没问题。问题是每个包独有的配置设置。为每个包设置环境似乎很疯狂。

这是一个问题:我有几十个包含有数百个配置值,这些配置值对于包是唯一的。如果我不能像2008年那样在表格中存储和检索这些值,那么你们在2014年如何做到这一点?

2 个答案:

答案 0 :(得分:4)

仅仅能够使用环境并不一定如此。虽然您仅限于开箱即用的配置选项,但我与团队合作,我们已经能够利用一个直接的系统将变量值传递给表中的包。环境包含一些连接信息,但是需要在运行时设置的任何变量值都存储为行数据。

在变量值表中,除了对包的引用外,一个字段包含变量名,另一个字段包含值。脚本任务调用存储过程并返回一组名称/值对,并且包中的变量将相应地分配传入的值。它是每个包的相同脚本代码。我们只需要确保表中的变量名与包中的变量名匹配。

结合日志记录数据已被证明是使用项目部署模型管理包的一种非常有效的方法。

实施例

这是一个简单的软件包,用于显示该过程。首先,创建一个包含变量值的表和一个存储过程,以返回您正在运行的包的相关集。我选择将它放在SSISDB中,但您可以使用几乎任何数据库来容纳这些对象。我也使用OLEDB连接,这很重要,因为我引用了使用OLEDB库的脚本任务中的连接字符串。

create table dbo.PackageVariableValues
(PackageName NVARCHAR(200)
, VariableName NVARCHAR(200)
, VariableValue NVARCHAR(200)
)

create proc dbo.spGetVariableValues
@packageName NVARCHAR(200)
as
SELECT VariableName, VariableValue
FROM dbo.PackageVariableValues
WHERE PackageName = @packageName

insert into dbo.PackageVariableValues
select 'Package', 'strVariable1', 'NewValue'
union all select 'Package', 'intVariable2', '1000'

对于这个例子,包本身只包含脚本任务和我们在运行时设置的几个变量。

package overview

我有两个变量strVariable1intVariable2。这些变量名称映射到我插入表中的行数据。

在Script Task中,我将PackageName和TaskName作为只读变量和将设置为读写的变量传递。

script variables

脚本任务中的代码执行以下操作:

  • 根据指定的连接管理器设置连接字符串
  • 构建存储过程调用
  • 执行存储过程并收集响应
  • 遍历每一行,设置变量名称和值
  • 使用try / catch / finally,脚本会返回一些日志记录详细信息以及失败时的相关详细信息

正如我前面提到的,我使用OLEDB库来连接SQL和执行程序。

imported libraries

这是脚本任务代码:

public void Main()
{
    string strPackageName;

    strPackageName = Dts.Variables["System::PackageName"].Value.ToString();

    string strCommand = "EXEC dbo.spGetVariableValues '" + strPackageName + "'";

    bool bFireAgain = false;

    OleDbDataReader readerResults;

    ConnectionManager cm = Dts.Connections["localhost"];
    string cmConnString = cm.ConnectionString.ToString();

    OleDbConnection oleDbConn = new OleDbConnection(cmConnString);

    OleDbCommand cmd = new OleDbCommand(strCommand);
    cmd.Connection = oleDbConn;

    Dts.Events.FireInformation(0, Dts.Variables["System::TaskName"].Value.ToString(), "All necessary values set. Package name: " + strPackageName + " Connection String: " + cmConnString, String.Empty, 0, ref bFireAgain);

    try
    {
        oleDbConn.Open();
        readerResults = cmd.ExecuteReader();

        if (readerResults.HasRows)
        {
            while (readerResults.Read())
            {

                var VariableName = readerResults.GetValue(0);
                var VariableValue = readerResults.GetValue(1);

                Type VariableDataType = Dts.Variables[VariableName].Value.GetType();
                Dts.Variables[VariableName].Value = Convert.ChangeType(VariableValue, VariableDataType);

            }

            Dts.Events.FireInformation(0, Dts.Variables["System::TaskName"].Value.ToString(), "Completed assigning variable values.  Closing connection", String.Empty, 0, ref bFireAgain);
        }
        else
        {
            Dts.Events.FireError(0, Dts.Variables["System::TaskName"].Value.ToString(), "The query did not return any rows", String.Empty, 0);
        }
    }
    catch (Exception e)
    {

        Dts.Events.FireError(0, Dts.Variables["System::TaskName"].Value.ToString(), "There was an error in the script.  The messsage returned is: " + e.Message, String.Empty, 0);
    }
    finally
    {
        oleDbConn.Close();
    }
}

设置值的部分有两个需要注意的重要事项。首先,设置为查看结果集中每行的前两列。您可以更改此值或将其他值作为行的一部分返回,但是您正在使用基于0的索引,并且如果可以避免,则不希望返回一堆不必要的列。

            var VariableName = readerResults.GetValue(0);
            var VariableValue = readerResults.GetValue(1);

其次,由于表中的VariableValues列可以包含需要在变量中进行不同类型的数据,因此我采用变量数据类型并对值进行转换以验证它是否匹配。由于这是在try / catch中完成的,因此导致的失败将返回我可以在输出中看到的转换消息。

            Type VariableDataType = Dts.Variables[VariableName].Value.GetType();
            Dts.Variables[VariableName].Value = Convert.ChangeType(VariableValue, VariableDataType);

现在,结果(通过Watch窗口):

<强>之前

package variables before

之后

package variables after

在脚本中,我使用fireInformation返回脚本任务的反馈以及catch块中的任何fireError。这使得在调试期间以及查看SSISDB执行消息表(或执行报告)时可读输出

execution output messages

为了显示错误输出的示例,这里是从转换失败的过程传递的错误值。

error output

希望这足以让你继续下去。我们发现这是非常灵活但易于管理的。

答案 1 :(得分:0)

配置SSIS包时,您有3个选项:使用设计时间值,手动编辑值并使用环境。

方法1

我找到了最后两个混合物的成功。我创建了一个文件夹:Configuration和一个环境Settings。没有项目部署到配置。

我在设置环境中填充了可能跨项目共享的任何内容。数据库连接字符串,ftp用户和密码,公共文件处理位置等。

对于已部署的项目,我们发现需要配置的内容通过显式覆盖进行处理。例如,文件名因环境而异,因此我们已经通过编辑器设置了值,但我们没有单击“确定”,而是单击顶部的“脚本”按钮。这会产生类似

的调用
DECLARE @var sql_variant = N'DEV_Transpo*.txt';
EXEC SSISDB.catalog.set_object_parameter_value
    @object_type = 20
,   @parameter_name = N'FileMask'
,   @object_name = N'LoadJobCosting'
,   @folder_name = N'Accounting'
,   @project_name = N'Costing'
,   @value_type = V
,   @parameter_value = @var;

我们存储脚本并在迁移过程中运行它们。它导致一些脚本看起来像

SELECT @var = CASE @@SERVERNAME
    WHEN 'SQLSSISD01' THEN N'DEV_Transpo*.txt'
    WHEN 'SQLSSIST01' THEN N'TEST_Transpo*.txt'
    WHEN 'SQLSSISP01' THEN N'PROD_Transpo*.txt'
    END

但这是一次性任务,所以我不认为这是繁重的。关于我们的东西是如何工作的假设是,一旦我们弄清楚它,它就是静态的,所以一旦它工作就没有多少流失。供应商很少重新定义他们的命名标准。

方法2

如果您发现这种方法不合理,那么可能会继续使用表来配置动态的东西。我可以看到两个实现工作。

选项A

第一个是从外部演员设置的。基本上,从上面的配置步骤,但不是存储静态脚本,一个简单的光标将应用它们。

--------------------------------------------------------------------------------
-- Set up
--------------------------------------------------------------------------------
CREATE TABLE dbo.OptionA
(
    FolderName sysname
,   ProjectName sysname
,   ObjectName sysname
,   ParameterName sysname
,   ParameterValue sql_variant
);

INSERT INTO
    dbo.OptionA
(
    FolderName
,   ProjectName
,   ObjectName
,   ParameterName
,   ParameterValue
)
VALUES
(
    'MyFolder'
,   'MyProject'
,   'MyPackage'
,   'MyParameter'
,   100
);
INSERT INTO
    dbo.OptionA
(
    FolderName
,   ProjectName
,   ObjectName
,   ParameterName
,   ParameterValue
)
VALUES
(
    'MyFolder'
,   'MyProject'
,   'MyPackage'
,   'MySecondParameter'
,   'Foo'
);

上面简单地创建了一个表,该表标识了应该应用的所有配置以及它们应该去的位置。

--------------------------------------------------------------------------------
-- You might want to unconfigure anything that matches the following query.
-- Use cursor logic from below substituting this as your source

--SELECT
--    *
--FROM
--    SSISDB.catalog.object_parameters AS OP
--WHERE
--    OP.value_type = 'V'
--    AND OP.value_set = CAST(1 AS bit);
-- 
-- Use the following method to remove existing configurations
-- in place of adding them
--
--EXECUTE SSISDB.catalog.clear_object_parameter_value
--    @folder_name = @FolderName
--    @project_name = @ProjectName
--    @object_type = 20
--    @object_name = @ObjectName
--    @parameter_name = @ParameterName 
--------------------------------------------------------------------------------

从而开始应用配置

--------------------------------------------------------------------------------
-- Apply configurations
--------------------------------------------------------------------------------

DECLARE
    @ProjectName sysname
,   @FolderName sysname
,   @ObjectName sysname
,   @ParameterName sysname
,   @ParameterValue sql_variant;

DECLARE Csr CURSOR
READ_ONLY FOR 
SELECT
    OA.FolderName
,   OA.ProjectName
,   OA.ObjectName
,   OA.ParameterName
,   OA.ParameterValue
FROM
    dbo.OptionA AS OA

OPEN Csr;
FETCH NEXT FROM Csr INTO
    @ProjectName
,   @FolderName
,   @ObjectName
,   @ParameterName
,   @ParameterValue;

WHILE (@@fetch_status <> -1)
BEGIN
    IF (@@fetch_status <> -2)
    BEGIN

        EXEC SSISDB.catalog.set_object_parameter_value
            -- 20 = project
            -- 30 = package
            @object_type = 30
        ,   @folder_name = @FolderName
        ,   @project_name = @ProjectName
        ,   @parameter_name = @ParameterName
        ,   @parameter_value = @ParameterValue
        ,   @object_name = @ObjectName
        ,   @value_type = V;

    END
    FETCH NEXT FROM Csr INTO
        @ProjectName
    ,   @FolderName
    ,   @ObjectName
    ,   @ParameterName
    ,   @ParameterValue;

END
CLOSE Csr;
DEALLOCATE Csr;

你什么时候跑?每当需要运行时。您可以在OptionA上设置触发器以使其紧密同步或将其作为后部署过程的一部分。真的,无论你的组织有什么意义。

选项B

这与Vinnie的建议大相径庭。我将设计一个Parent / Orchestrator包,负责查找项目的所有可能配置,然后填充变量。然后,使用带有项目部署模型的子包的清除变量传递。

就个人而言,我并不关心这种方法,因为它对实施解决方案以使编码正确的开发人员承担更多责任。我发现它的维护成本较高,而且并非所有BI开发人员都对代码感到满意。并且该脚本需要在一系列父类型包中实现,并且往往导致复制和粘贴继承,并且没有人喜欢它。