什么是 SSIS 包部署和更改跟踪最佳实践?

Posted

技术标签:

【中文标题】什么是 SSIS 包部署和更改跟踪最佳实践?【英文标题】:What are SSIS packages deployment and change-tracking best practices? 【发布时间】:2009-10-15 10:05:24 【问题描述】:

关于我的 SQL 数据库架构和数据,我有一个非常强大的开发环境(一切都是源代码控制的,部署是自动化的,等等),但是当涉及到 SSIS 包时,这个过程非常乏味并且完全是手动的。

如何自动化 SSIS 包升级过程(现在,我手动将包复制到每台服务器,然后使用 Management Studio 的“SSIS 包升级向导”)

如何部署我的计划(现在,我正在手动进行)

如何部署我的 SQL 代理作业(现在,我正在手动进行)

如何在我的 TeamSystem 存储库中获取我的日程安排和作业(目前,我没有为此使用源代码控制)

我可以/应该做些什么来改进我在 SSIS 包方面的工作方式?

我使用的是 MS SQL Server 2008 SP1,但我想一些建议在其他版本上也可能有用。

【问题讨论】:

关于它的任何最终解决方案?有什么最终结论吗? 【参考方案1】:

第 1 点(自动化部署):

可以使用dtutil.exe 从命令行部署 SSIS 包。

以下示例会将本地文件 c:\test.dtsx 部署到名为 test_packageserver1 上的 MSDB 存储:

dtutil.exe /FILE C:\test.dtsx /dests server1 /COPY SQL;test_package

如果您可以计算出要使用的参数组合,它将对所有各种 SSIS 存储选项执行任何导入/导出组合。

这可能与您无关,但这不会(向导会)复制配置文件;你需要一个单独的批处理步骤。

关于第 2 点和第 3 点(SQL 代理的源代码控制):

正如其他人所说,SQL 代理作业和计划可以编写为 T-SQL(在 Management Studio 中,右键单击作业并选择 Script job to...),保存在源代码控制中,并像任何其他 T-SQL 一样部署脚本。

我们的数据库源代码控制树设置为每个生产服务器一个文件夹,每个用户数据库包含一个子文件夹以及一个名为_config 的额外子文件夹,其中包含用于服务器级对象(例如登录名、链接服务器和 SQL 代理作业)的脚本。

(这与您的问题并不真正相关,但我们将 SSIS 包存储在它们自己的树中,因为它们可以应用于多个服务器)

我们不使用 TFS,因此我无法评论将脚本放入其中的细节。

【讨论】:

【参考方案2】:

我们所做的就是将所有内容保存在源代码管理中。我们的 SSIS 包被保存为 DTSX 文件,并被放入我们的源代码控制中。我们使用所有东西的源代码控制版本来推广到 QA 和 Prod。我们使用为管理 SSIS 包的元数据而设置的数据库中的配置表对 SSIS 包进行所有配置。这通常由我们所有的连接字符串以及我们可能希望在运行时设置的一些变量组成。我们还在此数据库中设置了所有日志记录。这样做的好处之一是上传正在更改的包变得容易得多,因为配置表通常不需要更改,只需将修改后的 dtsx 文件加载到它将运行的位置。即使我们需要为配置表添加新的引用,这也是对表的插入,并且很容易为升级过程编写脚本。

您还可以使用配置 xml 文件轻松更改配置(这些也可以存储在源代码管理中),但我们更喜欢将所有内容都放在我们存储元数据的 ETL 数据库中。

【讨论】:

【参考方案3】:
    我不知道升级包是否可以自动化。 部署 SSIS 包create a Manifest file 您可以write SQL scripts to create SQL schedules and jobs 然后使用一些 vb.net 脚本或其他方式调用此脚本。 要将 SQL 脚本添加到 TFS,请打开 SQL Server Management Studio > 文件 > 新建 > 项目 > SQL Server 脚本。将脚本添加到 Queries 文件夹,然后您可以将此解决方案添加到 TFS。我从来没有试过这个。相反,我手动将脚本文件复制到 TFS。

在我看来,创建一个完整的部署实用程序来部署 SSIS 包是没有意义的,因为这是一种非常罕见的活动。当我们向非技术用户分发软件产品时,部署/安装应该很简单,以便用户友好。但是 SSIS 包将始终由 DBA 或已经知道如何使用它的人处理...

【讨论】:

【参考方案4】:

关于第 1 点,请参阅本网站 http://jessicammoss.blogspot.com/2008/05/ssis-configuration-to-configuration-to.html

不久前我也有同样的问题,这个网站帮了很多忙。 我对其他点以及我的团队像您一样手动部署它们感到好奇,但我想我会分享我所知道的。

【讨论】:

【参考方案5】:

关于编写对象的脚本,您可以通过 DMO、SMO、PowerShell、VBScript 和任何其他数量的方法来完成。我仍然使用我编写的古老的 VB DMO 脚本,该脚本基于来自多个网站的代码,并通过 SSIS 脚本任务执行代码。设置执行包的 SQL Server 代理作业并添加签入代码的步骤。我不熟悉 TFS,但我已经使用 Visual SourceSafe 和 Perforce 完成了这项工作,没有任何问题。诀窍是您只需要学习如何进行无人值守的命令行签入来合并更改(更新、删除、创建)。下面是我古老的 VB.NET 脚本任务。请记住,您可以将其中的一部分替换为变量以使其更具动态性。

' Microsoft SQL Server Integration Services Script Task
' Write scripts using Microsoft Visual Basic 2008.
' The ScriptMain is the entry point class of the script.

Imports System
Imports System.Data
Imports System.Math
Imports Microsoft.SqlServer.Dts.Runtime
Imports System.IO
Imports System.Text.RegularExpressions


<System.AddIn.AddIn("ScriptMain", Version:="1.0", Publisher:="", Description:="")> _
Partial Class ScriptMain

Private Sub ScriptMain_Startup(ByVal sender As Object, ByVal e As System.EventArgs)

End Sub

Private Sub ScriptMain_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs)
    Try
        ' Unlock variables from the read-only and read-write variable collection properties
        If (Dts.Variables.Count <> 0) Then
            Dts.Variables.Unlock()
        End If
    Catch ex As Exception
    End Try
End Sub

Enum ScriptResults
    Success = DTSExecResult.Success
    Failure = DTSExecResult.Failure
End Enum
Private Function CleanFileName(ByVal FileName As String) As String


    FileName = Regex.Replace(FileName, "[/\\:?=*<>]", "-")
    Return FileName

End Function







Public Sub Main()

    ''THESE MUST BE SET AND THE AGENT ACCOUNT MUST HAVE WRITE ACCESS TO THE DRIVE SELECTED
    Dim FolderName = "\\Your\Folder\Hierarchy\"
    Dim ServerName = "your-server-name"

    Dim ScriptOptions As Integer
    ScriptOptions = 1 ' Generate Drop
    ScriptOptions = ScriptOptions Or 4 ' Generate Default (Create)
    ScriptOptions = ScriptOptions Or 34 ' Generate Permissions (Database & Object)

    Dim ScriptOptions_Jobs As Integer
    ScriptOptions_Jobs = 1 ' Generate Drop
    ScriptOptions_Jobs = ScriptOptions_Jobs Or 1203765415 ' Other stuff


    Dim ScriptOptions_Tables As Integer
    ScriptOptions_Tables = 1 ' Generate Drop
    ScriptOptions_Tables = ScriptOptions_Tables Or 4 ' Generate Default (Create)
    ScriptOptions_Tables = ScriptOptions_Tables Or 34 ' Generate Permissions (Database & Object)
    ScriptOptions_Tables = ScriptOptions_Tables Or 73736 ' Generate Indexes

    Dim EXCLUDE_LIST = "master/tempdb/model/msdb"

    ''Standardize the end of the folder name to include \.
    If Right(FolderName, 1) <> "\" Then
        FolderName = FolderName & "\"
    End If

    ''Declare a folder that can be deleted.  Delete doesn't like ending with \.
    Dim FolderNameDelete = FolderName
    If Right(FolderNameDelete, 1) = "\" Then FolderNameDelete = _
        Left(FolderNameDelete, Len(FolderNameDelete) - 1)

    'Used for file system tasks.
    Dim oFSO = CreateObject("Scripting.FileSystemObject")

    'Delete if the folder exists.  If you don't delete the folder and populate the scripts,
    'then objects that were deleted from the database won't disappear and the Perforce diff
    'won't recognize that the objects need to be deleted in Perforce.
    If oFSO.FolderExists(FolderName) = True Then
        oFSO.DeleteFolder(FolderNameDelete, True)
    End If

    'Create the folder now so that we have a clean script destination.
    oFSO.CreateFolder(FolderName)
    oFSO.CreateFolder(FolderName & "Databases")
    oFSO.CreateFolder(FolderName & "Jobs")

    'connect to the server instance using trusted credentials so we dont have password stored in a file and we dont have
    'to worry about password changes breaking anything
    Dim oServer = CreateObject("SQLDMO.SQLServer")
    With oServer
        .LoginSecure = True
        .Connect(ServerName)
    End With

    'Script out SQL Server Agent Jobs.
    For Each oJob In oServer.JobServer.Jobs
        oJob.Script(ScriptOptions_Jobs, FolderName & "Jobs\" & CleanFileName(oJob.Name) & ".sql")
    Next


    'loop through all databases and excluding those in the EXCLUDE_LIST above, script out all the stored procedures.
    'You could easily change this to read from a table or to let you pass in a different list.
    For Each oDB In oServer.Databases

        If InStr(1, EXCLUDE_LIST, oDB.Name) = 0 Then

            'each db will get a folder in the main folder (FolderName) that will act as a container for the backup
            'folders we'll create each time we run this
            Dim dbFolder = FolderName & "Databases\" & oDB.Name & "\"

            oFSO.CreateFolder(dbFolder)
            oFSO.CreateFolder(dbFolder & "Stored Procedures")
            oFSO.CreateFolder(dbFolder & "Tables")
            oFSO.CreateFolder(dbFolder & "User-Defined Functions")
            oFSO.CreateFolder(dbFolder & "Views")

            'script out all the non-system procs
            For Each oProc In oDB.StoredProcedures
                If oProc.SystemObject = False Then
                    ''262150= SQLDMOScript_ObjectPermissions + SQLDMOScript_PrimaryObject + SQLDMOScript_OwnerQualify
                    oProc.Script(ScriptOptions, dbFolder & "\Stored Procedures\" & CleanFileName(oProc.Owner) & "_" & CleanFileName(oProc.Name) & ".sql")
                End If
            Next

            'script out all the non-system views
            For Each oView In oDB.Views
                If oView.SystemObject = False Then
                    ''262150= SQLDMOScript_ObjectPermissions + SQLDMOScript_PrimaryObject + SQLDMOScript_OwnerQualify
                    oView.Script(ScriptOptions, dbFolder & "\Views\" & CleanFileName(oView.Owner) & "_" & CleanFileName(oView.Name) & ".sql")
                End If
            Next

            'script out all the non-system user-defined functions
            For Each oUDF In oDB.UserDefinedFunctions
                If oUDF.SystemObject = False Then
                    ''262150= SQLDMOScript_ObjectPermissions + SQLDMOScript_PrimaryObject + SQLDMOScript_OwnerQualify
                    oUDF.Script(ScriptOptions, dbFolder & "\User-Defined Functions\" & CleanFileName(oUDF.Owner) & "." & CleanFileName(oUDF.Name) & ".sql")
                End If
            Next

            'script out all the non-system tables
            For Each oTable In oDB.Tables
                If oTable.SystemObject = False Then
                    ''262150= SQLDMOScript_ObjectPermissions + SQLDMOScript_PrimaryObject + SQLDMOScript_OwnerQualify
                    oTable.Script(ScriptOptions_Tables, dbFolder & "\Tables\" & CleanFileName(oTable.Owner) & "_" & CleanFileName(oTable.Name) & ".sql")
                End If
            Next


        End If
    Next

    'close it all out
    oServer.DisConnect()
    oServer = Nothing
    oFSO = Nothing

    Dts.TaskResult = ScriptResults.Success
End Sub

结束类

【讨论】:

【参考方案6】:

使用 Powershell 脚本和 dtutil.exe 实用程序。

例如,示例源代码,可能有任何错误,来自 maxt2posh 博客(匿名评论):

#get the location of DTUTIL
$DTSPath = (get-itemproperty -path “HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\100\SSIS\Setup\DTSPath”).’(default)’
#get the names of the packages in the current windows folder
$PackageNames = Get-ChildItem -Name -Filter “*.dtsx”
#The SSIS or Filesystem folder where the packages will be installed
$InstallTargetFolder = “”
#The SSIS or Filesystem folder where the existing packages will be backed up
$BackupFolder = “MattBKUP\”

function RUNINSTALL()

cls
Write-Host “.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^”
foreach ($name in $PackageNames )

InstallPackage $name.TrimEnd().ToString()
Write-Host “………………………………………………………….”

Write-Host ” ”
Write-Host ” ”
Write-Host “……………….DONE”



#copy all packages in the BackupFolder to the InstallFilder and delete the Backup Folder
#get the list of files in the $BackupFolder
#move them to the $InstallTargetFolder
function RollbackPackages 
Write-Host “ROLLING BACK…………………..”
foreach ($name in $PackageNames )

Write-Host “ROLLING BACK PACKAGE ” + $Name
[String]$From = $BackupFolder + $Name.Replace(“.dtsx”,”")
[String]$To = “SQL;” + $InstallTargetFolder + $Name.Replace(“.dtsx”,”")
Write-Host “Restoring PACKAGE From:” + $From + ” TO:” + $To
[String]$Status = dtutil /SQL $From /MOVE $To /quiet




#Move the Package $Name From $InstallTargetFolder to $BackupFolder
function BackupPackage  param( [String]$Name, [String]$Status )
[String]$From = $InstallTargetFolder + $Name.Replace(“.dtsx”,”")
[String]$To = “SQL;” + $BackupFolder + $Name.Replace(“.dtsx”,”").ToString()
[String]$ToPath = “SQL;” + $BackupFolder
#package exists?
[String]$PackageExists = dtutil /SQL $From /Ex /quiet
if($PackageExists.Contains(“The specified package exists”) )

#backup folder exists?
[String]$FolderExists = dtutil /Fe $ToPath /quiet
if($FolderExists.Contains(“The specified folder does not exist”) )

[String]$CreatePath = “SQL;\;” + $BackupFolder.TrimEnd(‘\’)
Write-Host “Creating Backup folder:” $CreatePath
#/FC[reate] SQL | DTS;ParentFolderPath;NewFolderName
[String]$Status = dtutil /FC $CreatePath /quiet

Write-Host “BACKING UP PACKAGE From:” $From ” TO:” $To
[String]$Status = dtutil /SQL $From /COPY $To /quiet

else
Write-Host “Backup not required for:” $From


function ValidateInstall 
param([String]$Name,[String]$Status)

if ( $LASTEXITCODE -eq 0)

Write-Host “Package Deployment Success ” $Name

else

if
( $LASTEXITCODE -eq 1) Write-Host “Package Deployment Failed ” + $Name + ” …*** ERROR *** The utility failed. Error code 1 ” + $status 
elseif
($LASTEXITCODE -eq 4) Write-Host “Package Deployment Failed ” + $Name + ” …*** ERROR *** The utility cannot locate the requested package. Error code 4 ” + $status 
elseif
($LASTEXITCODE -gt 5) Write-Host “Package Deployment Failed ” + $Name + ” …*** ERROR *** The utility cannot load the requested package. Error code 5 ” + $status 
elseif
($LASTEXITCODE -gt 6) Write-Host “Package Deployment Failed ” + $Name + ” …*** ERROR *** The utility cannot resolve the command line because it contains either syntactic or semantic errors. Error code 6 ” + $status 
else
“Package Deployment Failed ” + $Name + ” …*** ERROR *** Unidentified Error. ” + $status 

RollbackPackages
Write-Host ” ”
Write-Host “ROLLBACK COMPLETE”
Write-Host ” ”
Read-Host “Press enter to continue …”

Exit



function InstallPackage  param( [String]$Name, [String]$Status )
backuppackage $Name $Status
[String]$To = “SQL;” + $InstallTargetFolder + $Name.Replace(“.dtsx”,”")
$Status = dtutil /FILE $Name /COPY $To /quiet
ValidateInstall $Name $Status

参考文献:

Script by Chad Miller

http://maxt2posh.wordpress.com/2010/04/23/deploying-ssis-packages-using-dtutil-exe-with-powershell-part-1%E2%80%A6/

http://billfellows.blogspot.com.es/2010/05/powershell-dtutil-ssisdeploymanifest.html

dtutil Utility

Sql PSX

http://www.katieandemil.com/powershell-dtutil

【讨论】:

以上是关于什么是 SSIS 包部署和更改跟踪最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章

最佳实践 - iOS 中的 NSManagedObjectContextObjectsDidChangeNotification

(Java)包组织有最佳实践吗? [关闭]

将SSIS 2016包(项目部署模型)部署到文件系统

最佳设计模式——用于 DWH 加载的 SSIS 包

Android Studio Logcat是最佳实践

如何更改 VectorDrawable viewportHeight 和 viewportWidth 以及使用矢量的最佳实践是啥?