Friday, July 8, 2011

How to insert and update table in SSIS (Upsert or Merge)?

Source:http://pragmaticworks.com/forum/yaf_postsm46_How-to-insert-and-update-table-in-SSIS--Upsert-or-Merge.aspx#post46

Many times you have need to Insert new record or Update existing record in target table using SSIS. This can be done in 2 ways.

1. Combination of OLEDB Destination and OLEDB Command. This approach can be very slow if you have lots of updates. For large amount of records please check the next approach.
http://beingoyen.blogspo...e-instead-of-insert.html



2. Using TaskFactory Upsert Destination.
http://pragmaticworks.co...p_Upsert_Destination.htm

Upsert Destination Tutorial

http://pragmaticworks.co...rt_Destination_Video.htm

Upsert Destination (Batch Update Or Insert)

 SSISUpsert Destination Helps synchronize two systems no matter the source or destination. Many companies struggle with the development of loading procedures that determine whether the row is new or to be updated. The Upsert Destination reads the rows coming into the data flow and detects if the row should be inserted or updated. This saves the developer a long development cycle and could save up to 90% on each execution of a package.

Key Features:
  • Conditionally inserts or updates data into a table. Inserts are performed using bulk insert which is significantly faster compared to row-by-row approach. There are four methods in which data can be updated giving the user a great amount of control on whether data should be updated or not.
    1. Bulk update - Updates will be performed in the fastest amount of time because no data compare is performed. This is by far the fastest way to perform updates
    2. Column Compare - Updates will only be performed based on what columns the user selects to compare. If the data in the selected columns does not match, the update will be performed. Otherwise it will be ignored.
    3. DateTime Compare - Updates will only be performed based on a datetime column being compared from the source to a column in the destination.
    4. Timestamp Compare - Updates will only be performed based on a timestamp column being compared from the source to a column in the destination.
  • Currently supports SQL 2005 and SQL 2008 as destination
  • Easy to use User Interface











SSIS Upsert Test

SSIS auto generate update scripts

Specify the TableName in @TableName variable to create the Update script to be used for SSIS.

DECLARE @counter int;
DECLARE @QueryString nvarchar(2400) = ''
DECLARE @ColumnName nvarchar(120);
DECLARE @TableName nvarchar(120) = 'MyTable'
CREATE TABLE #ColumnList
(
ID int IDENTITY(1,1)
,ColumnName varchar(1200)
)
INSERT #ColumnList
select sys.columns.name from sys.columns
inner join sys.tables on sys.tables.object_id = sys.columns.object_id
where sys.tables.name = @TableName
and sys.columns.name <> 'ID'
SET @counter = 1
SET @QueryString = 'UPDATE dbo.' + @TableName + '
SET '
SET @ColumnName = (SELECT ColumnName FROM #ColumnList WHERE ID=@counter)
SET @QueryString = @QueryString + '
' + @ColumnName+ ' = ? '
SET @counter = @counter + 1;
WHILE @counter <= (SELECT COUNT(*) FROM #ColumnList)
BEGIN
SET @ColumnName = (SELECT ColumnName FROM #ColumnList WHERE ID=@counter)
SET @QueryString = @QueryString + '
,' + @ColumnName+ ' = ? '
SET @counter = @counter + 1;
END
SET @QueryString = @QueryString + '
WHERE ID = ?;'
PRINT @QueryString
DROP TABLE #ColumnList


source: http://beingoyen.blogspot.com/2010/03/ssis-auto-generate-update-scripts.html

SQL Server在什么样的条件下需要重建索引

 问:在什么样的条件下需要重建索引?
答:重建索引需要如下两个条件。
一:分析(analyze)指定索引之后,查询index_stats的height字段的值,如果这个值>=4 ,最好重建(rebuild)这个索引。虽然这个规则不是总是正确,但如果这个值一直都是不变的,则这个索引也就不需重建。
二:在分析(analyze)指定索引之后,查询index_stats的del_lf_rows和lf_rows的值,如果(del_lf_rows/lf_rows)*100 > = 20,则这个索引也需要重建。
举例如下:
SQL > analyze index IND_PK validate structure;
SQL > select name,height,del_lf_rows,lf_rows,
(del_lf_rows/lf_rows) *100 from index_stats;
NAME    HEIGHT DEL_LF_ROWS  LF_ROWS (DEL_LF_ROWS/LF_ROWS)*100
------------------------------
INDX_PK  4   277353   990206   28.0096263
SQL> alter index IND_PK rebuild;

运用SQL Server 2005 SSIS变量

一、 SSIS变量简介
SSIS(SQL Server Integration Services,SQL Server整 合服务)变量分为两种,一种是系统变量,一种用户定义的变量。系统变量包含有关包、容器、任务或事件处理程序的非常有用的信息。例如,在运行 时,MachineName 系统变量包含运行包的计算机的名称,StartTime 变量包含包开始运行的时间。系统变量是只读的。在 SSIS 中,用户变量是用户在开发的过程中根据需要申明的变量。用户变量可以使用在脚本中,在由优先约束、For 循环容器、派生列转换和条件性拆分转换使用的表达式中,以及在更新属性值的属性表达式中。
在各种编程语言中申明的变量一般情况下都会有 作用范围的,SSIS变量也不例外,SSIS变量也是有作用范围的。根据作用范围分类,变量分为包变量和组件变量。包变量在包任何一个组件中都可以调用, 组件变量只能够在申明变量的组件中有效。在变量的窗口中可以看到变量的作用域(如图1所示)。BeginDate就是TestPackage包变量,而i 是数据转换这个数据流组件的变量。
如何灵活运用SQL Server 2005 SSIS变量
图1
二、 SSIS用户变量的申明、赋值、使用
1、 申明变量
申明变量非常简单,如果你要申明包变量,只要单击控制流选项卡,然后在包开发区域空白处单击右键选择变量命令(出现如图1的画面),单击新建变量按钮就新建一个变量,输入名称,选择数据类型,赋初值就完成了 (如图2)。
红色方框是新建变量按钮,蓝色方框是删除按钮。如果要申明某数据流任务组件使用的变量,只要双击该数据流任务组件,在流控制选项卡空白的地方单击右键选择变量命令,在变量窗口中新建一个变量,这时变量的作用域就是你所选的流任务组件。
如何灵活运用SQL Server 2005 SSIS变量
图2
2、 赋值
在实际开发中,除了在变量申明的时候给变量赋值外,笔者还摸索了两种方式给变量赋值,一种是通过执行 SQL 任务组件返回值的方式给变量赋值,一种是通过脚本组件来给变量赋值。
利用执行 SQL 任务组件方法是先设置好组件的数据库连接属性,然后输入从数据取数据的SQL语句,设置组件返回的结果集为单行。在结果集界面中单击“新建“,在结果集那 一列输入你刚才SQL 语句中返回列的名称,在变量名称列选择你要赋值的变量(过程如图3、图4所示)。
如何灵活运用SQL Server 2005 SSIS变量
图3
如何灵活运用SQL Server 2005 SSIS变量
图4
图3中红色方框中SQL语句非常简单,返回单行,结果是1。在图4中,将返回的result列的一行赋值给用户变量i。
利用脚本组件赋值变量比较简单,只需要设置脚本组件的ReadOnlyvariable或者ReadWriteVariable,将变量的名称设置为他们的值(多个变量以逗号分隔),它们的区别是前者在脚本组件只能够读,后者可以读写。然后在脚本组件中通过
Dts.Variables("i").Value = 1
3、 变量的使用
变量在ssis中使用的地方很多,笔者介绍两个典型的应用。
(1) 执行 SQL 任务组件的参数
假定申明了一个日期类型变量StartDate,用户需要通过从某个表中选择在StartDate日期之前的数据,这个时候需要将StartDate作为参数传给执行 SQL 任务组件。在执行 SQL 任务组件输入SQL的地方输入如下命令语句:
SELECT * FROM TABLE_a WHERE 日期字段 < ?
然后在参数据映射界面新增映射,在变量名称列选择用户变量StartDate,选择类型为DATE,在参数名称列输入给参数取的名称。这样就可以将StartDate变量传给SQL任务组件的SQL语句了。
(2) 在脚本组件中赋值
可以在脚本组件中通过Dts.Variables("i").Value = 1方式赋值给变量,也可以通过这种方式来使用变量。比如Dts.Variables("other_variable").Value = Dts.Variables("i").Value+1,这个语句是可以在脚本组件中执行的,将i变量加1后赋值给另外一个变量。

正确理解.NET和SQL Server中“空值”

初学数据库编程的人,经常会对“空值”产生疑问,例如通过编程新建的一个表中所有数据皆显示为,手动添加并删除文字后又变成了空白;一个字符串类型的字段,明明没有填值,却不等于"";用ADO.NET从数据库中取值,每遇到有的就出错……这需要我们正确认识.NET和SQL Server中几种不同的“空值”。
1:真正的空值
等同“没有输入的值”,可以出现在大多数类型的字段中(如果没有别的约束条件),SQL server中表示为null,显示为,手工在SQL Server企 业管理器中输入的方法是按Ctrl+0。它在.NET中对应System.DBNull.Value。在T-SQL命令中,判断一个值是不是空值,要用 “is null”而不是“= null”;处理空值有个ISNULL函数,它使用指定的值替换null。用ADO.NET从数据库得到的空值无法自动转化为空字符串或Nothing, 须手动检测:如果得到System.DBNull.Value,则赋给数据对象Nothing或其它自定义的有意义的值。
2:空字符串(零长度字符串),只出现在字符串类型(如nvarchar)的字段中,SQL server中表示为’’,显示为空白,手工在SQL Server企业管理器中输入时清空一个单元格即可。它在.NET中对应System.String.Empty,也就是我们常用的""。在T-SQL命令中处理空字符串和处理一般的字符串没什么区别。用ADO.NET从数据库得到的空字符串也和一般的字符串没什么区别。
相关的概念还有VB.NET中的Nothing和对应于C#.NET中的null(注意这个null是C#.NET中的null而非SQL Server中null),它们在.NET中是表示不引用任何对象的空引用的值,在传入SQL server时,根据不同的上下文环境,可能存为真正的空值(比如在更新一个字符串类型的字段值时),也可能调用在SQL server中自定义的默认值(比如传给一个有默认值的存储过程参数),也可能因为无法进行类型转换而引发.NET异常。因此在用ADO.NET向SQL Server中存储数据时,大家一定要小心使用Nothing。

统计SQL Server用户数据表大小

在SQL Server,简单的组合sp_spaceused和sp_MSforeachtable这两个存储过程,可以方便的统计出用户数据表的大小,包括记录总数和空间占用情况,非常实用,在SqlServer2K和SqlServer2005中都测试通过。
/**//*
1. exec sp_spaceused '表名'      (SQL统计数据,大量事务操作后可能不准)
2. exec sp_spaceused '表名', true    (更新表的空间大小,准确的表空大小,但可能会花些统计时间)
3. exec sp_spaceused          (数据库大小查询)
4. exec sp_MSforeachtable "exec sp_spaceused '?'"   (所有用户表空间表小,SQL统计数据,,大量事务操作后可能不准)
5. exec sp_MSforeachtable "exec sp_spaceused '?',true"  (所有用户表空间表小,大数据库慎用)
*/
create table #t(name varchar(255), rows bigint, reserved varchar(20), data varchar(20), index_size varchar(20), unused varchar(20))
exec sp_MSforeachtable "insert into #t exec sp_spaceused '?'"
select * from #t
drop table #t

另外还有sp_MSforeachdb可以遍历所有数据库,使用方法详见SQL帮助。

从SQL Server数据库管理员到数据仓库管理员

不管企业在Oracle还是SQL Server的 平台上构建了数据仓库都只是一个开始,要令这个仓库正常运转还需要有另外一群人的不懈努力,这就是数据仓库管理员(DWA)。他们和数据库管理员 (DBA)很相似,但又有所区别。想知道数据仓库管理员都要担负起哪些职责和任务吗?想知道需要具备哪些技能和知识才能成为一名优秀的数据仓库管理员吗? 想知道数据库管理员和数据仓库管理员之间的关系和区别在哪里吗?下面为你一一道来。
数据仓库市场的火热也带动了国内很多企业对数据仓 库应用的需求,特别是一些大型企业和机构,如保险业等。目前国内一些企业在数据仓库项目开发完成后并没有专门培训特定的数据仓库管理员,大都是从开发团队 里挑选一些人留下来执行维护任务,因为即使在通常情况下,经过简单的指导一般的技术人员也没有能力维护这个复杂的系统,更不用说出现突发事件应该怎么处理 了。数据仓库的管理是不少企业数据仓库应用的软肋。要保证数据仓库系统的稳定性、可用性和高效性必须要有具备专业素养的数据仓库管理员来完成。
数据仓库管理员(Data Warehouse Administrator),如果取首英文字母简写为DWA,很多人会以为讲的是数据仓库架构师(Data Warehouse Architect),不过本文的主角是数据仓库管理员,而且主要讲述的是活跃在SQL Server平台上的数据仓库管理员。
数据仓库管理员主要负责维护企业数据仓库的完整性和可用性,包括数据的质量问题,确保数据仓库的正常持续运行。数据仓库管理员要管理的也许是容量上到5TB级的高可用性SQL Server 2005数据仓库,而且有遍布全球的有几十家分公司好几百名用户将其应用于商业智能和客户关系管理;也许只是被某公司总部十几个用户用作销售、客户和产品分析的300GB单服务器数据仓库。不管数据仓库管理员需要管理的是哪一种数据库,其最重要工作就是维护。

数据仓库系统每天都要进行大量的ETL操作,按照特定的时间间隔把数据抽取整合到数据仓库里。这个时间间隔也许是每隔一天、每隔一个星 期或每隔几个小时。DWA的其中一个主要任务就是监测这些ETL处理进程,确保其正常运作。监测ETL处理进程的任务非常重要,因为这个进程在不断地为数 据仓库供给数据原料。如果ETL处理进程运行不当,数据仓库里的数据就会过时;如果ETL处理进程运行到一半就卡壳了,那么数据仓库里的数据就会不完整; 如果ETL处理进程运行出错,那么存入的数据也会不正确;而如果数据不正确不完整,那么根据这些数据而制定的所有决策都会受到影响。这就是为什么确保 ETL进程由始至终正常运作的重要原因。
数据仓库管理员最好是向数据仓库主管汇报工作,不过有时候他们会向数据仓库架构师汇报。数据仓库管理员的关键任务包括以下几个方面(假设在SQL Server平台上运行):
· 监测每天(每星期)的ETL进程、数据转化服务工具包和SQL Server集成服务任务的运行
· 管理数据仓库的数据库,维护所有数据库服务器
· 管理分析服务立方体和服务器
· 管理报表服务和服务器(很可能是一个网络场)
· 管理数据挖掘模型和预测分析
· 管理数据仓库安全
· 制作数据仓库工作负荷和活动情况报表
· 向数据仓库批量上载新数据
· 安装补丁程序并执行更新升级
· 管理数据仓库端口
· 备份和检测还原所有数据仓库对象
· 与开发团队保持合作以部署代码
· 与业务团队保持联系以解决关于数据请求的问题
· 为终端用户组织培训班

· 帮助用户解决查询问题
数据仓库管理员需要具备的核心技术能力:
· 具有维护SQL Server数据库的经验
· 具备报表和分析服务的知识
· 充分了解数据仓库构建原理
· 熟悉维度建模
· 清楚如何管理SQL Server集成服务作业和数据转化服务工具包
· 最好具有MCDBA认证或者MCITP的BI认证
数据仓库管理员必须知道怎样对数据仓库进行性能调优,必须了解对维度数据存储的事实表调优和对联机事务处理系统的事务表调优之间的区别,必须清楚为什么简单恢复更适合于阶段和维度数据存储而完全恢复更适合于操作数据存储。
在一些企业里,数据仓库管理员还要负责维护报表和SQL Server集成服务。不过大多数情况下,这些任务都是由另外的数据仓库开发员负责的。如果企业使用商业智能和企业绩效管理工具,例如Business Objects、SAS、Cognos、Hyperion、MicroStrategy 和ProClarity等,很可能数据仓库管理员也要负责管理这类工具。还要企业会为报表服务端口配置SharePoint,所以SQL Server数据仓库管理员也要具备与Sharepoint相关的技能。
“数据仓库管理员”这个术语在Teradata、DB/2和Oracle的机构里的流行程度比在SQL Server机构里的更高。不过自从SQL Server 2005上市后,构建在微软平台上的数据仓库也越来越受欢迎了。我们期待明年二月底发布的SQL Server 2008在将来能够给SQL Server数据仓库管理员角色更多的用武之地。
现在我们已经了解了数据仓库管理员究竟是个什么角色,那么一个SQL Server数据库管理员怎样才能成功地转型为SQL Server数据仓库管理员呢?其实,SQL Server数据库是SQL Server数据仓库管理员的最佳候选人,比IT业内的其他职位更接近和符合SQL Server数据仓库管理员的标准。SQL Server数据库管理员需要负责管理SQL Server数据库,维护用户安全,配置SQL Server,备份数据库,管理磁盘空间,进行SQL Server打补丁和升级等等任务。所有这些技能都为执行SQL Server数据仓库任务提供了坚实的基础。

通常两者的技能差距就在于分析服务立方体。要熟练掌握SQL Server集成服务作业和报表服务的管理工作非常困难,这里的困难不是指开发难度而仅仅是指管理工作的难度。不过管理分析服务立方体则有点不一样,你必须花上一定时间来熟悉多维数据库的概念。如果所在企业同时还使用数据挖掘工具,那么还要花一定时间去学习如何维护数据挖掘模型。
除了分析服务立方体和数据挖掘以外,其他的技能差别就在于对数据仓库构建概念的知识了。SQL Server数 据仓库管理员必须熟悉数据仓库构建和维度建模的概念(例如事实表、维度表、缓慢变化维度、代理键、聚集表、概要表、维度层次结构、迟到数据以及一致性维度 等)以及缓慢变化维度Type 2中有效数据列的作用。数据仓库管理员还必须能够描述向事务事实表、周期快照事实表和累积快照事实表里加载数据的区别。
数据仓库构建概念是数据仓库管理员必须具备的基础知识。数据仓库管理员不需要拥有从头开始设计一个数据仓库的经验,不过必须具备一些关于数据仓库架构的 基础知识,例如数据仓库数据库和联机事务处理数据库之间有什么区别。这些基础知识的积累非常必要,因为会影响到调优、表分区操作(扩展分区和旧区归档)、 构建索引、查询和聚集操作等。理想状态下,数据仓库管理员还需要熟练掌握ETL过程的操作原理,例如关于数据是怎么从源系统抽取出来并装载到目标数据仓库 里的;这是因为前面提到数据仓库管理员的重要职责之一就是监测ETL进程,而且这些知识的有无可能会影响到备份策略的实施。数据仓库管理员必须清楚在重新 运行一个已经失败的ETL进程时,数据完整性会不会受到影响。
数据仓库管理员还需要深化对数据质量概念的认识。保证数据仓库中的数据准 确性和完整性绝对是一项关键任务。如果我们连数据仓库中的数据都无法信任,那拥有数据仓库还有什么意义呢?数据仓库管理员需要明白保证数据质量的机制,例 如在坏数据被加载进数据仓库之前,数据质量防火墙是怎样检测出这些坏数据的;而系统是如何报告这些坏数据并把它们纠正过来的。对数据质量控制过程有一个透 彻的了解将有助于数据仓库管理员维护数据的质量。
以上就是数据仓库管理员必须执行的任务和必须担负的责任,以及执行这些 任务所需要的技能和知识。如果有人希望走进数据仓库管理员大家庭,在此致以衷心的祝愿,希望一切顺利,不过要记住掌握扎实的技能和知识才是立足数据仓库管 理员角色的王道。随着数据仓库在国内市场的开拓,相信这个角色也会越来越吃香的。目前越来越多的企业在考虑利用SQL Server平台来构建数据仓库,这意味着对于SQL Server数据库管理员而言是个难得的好机会。鉴于SQL Server 2008在数据仓库功能方面做了很大的改善(例如,星型联接查询优化、利用数据压缩功能改善事实表查询性能、利用变化数据捕获功能优化ETL过程,利用 Merge命令来进行更新插入操作等),SQL Server数据仓库的吸引力将会越来越大。

SQL Server四类数据仓库建模方法

SQL Server四类数据仓库建模的方法主要分为以下四类。
第一类是关系数据库的三范式建模,通常我们将三范式建模方法用于建立各种操作型数据库系统。
第二类是Inmon提倡的三范式数据仓库建模,它和操作型数据库系统的三范式建模在侧重点上有些不同。
Inmon的数据仓库建模方法分为三层,第一层是实体关系层,也即企业的业务数据模型层,在这一层上和企业的操作型数据库系统建模方法是相同的;第二层 是数据项集层,在这一层的建模方法根据数据的产生频率及访问频率等因素与企业的操作型数据库系统的建模方法产生了不同;第三层物理层是第二层的具体实现。
第三类是Kimball提倡的数据仓库的维度建模,我们一般也称之为星型结构建模,有时也加入一些雪花模型在里面。维度建模是一种面向用户需求的、容易理解的、访问效率高的建模方法,也是笔者比较喜欢的一种建模方式。
第四类是更为灵活的一种建模方式,通常用于后台的数据准备区,建模的方式不拘一格,以能满足需要为目的,建好的表不对用户提供接口,多为临时表。

SSIS的检查点文件用法

如果你是一个ETL应用程序开发人员或是管理员,那么你可能会遇到的一个问题就是发生失败后重新运行整个ETL应用程序。从失败处重新运行应用程序通常是不可能的,这有许多原因,但是主要是由于很难执行日志记录和维护应用程序的每一步以及配置基于可用日志的执行。SQL Server集成服务提供了一个在某种程度上自动从失败处重启处理的机制。这个机制是通过使用检查点文件来提供的。它帮助我们配置ETL解决方案在发生一个执行错误后的执行流。这篇文章解释了检查点文件和集成服务的一些有用任务的使用。
这篇文章包括:
· 建立检查点文档
· 在for loop中的检查点用法
· 在事件中的检查点用法
· 其它约束
建立检查点文档
检查点文件的配置从建立三个包的属性开始:CheckpointFileName、CheckpointUsage、SaveCheckpoints。 这些属性在检查点分类下和包的属性一样有效(看分类视图的属性)。CheckpointFileName 运行我们设置检查点文件的路径。因为信息是以XML格式存储的,给这个文件一个XML扩展会更好,不过这不是必需的(例如D:Checkpoint Files/LoadDataPackage.xml)。
第二个属性,CheckpointUsage 告诉集成服务这个包是否需要一个检查点文件。它可以使用三个值。Never、IfExists和Always。Never 表示没有使用检查点文件,包的执行必须从头开始(或者失败后重启)。Always 要求每一个执行使用检查点文件。一旦设置为Always,没有检查点文件包就不能启动。IfExists表示如果只存在检查点文件,那么包使用检查点文 件。IfExists是CheckpointUsage最好的设置,因为如果包发生错误,那么将只存在检查点文件。记住,一旦设置了检查点设置,包会在执 行过程中在给定位置创建检查点文件,然后在成功执行后将它删除。只有在失败的情况下才会将检查点文件保留下来。

SaveChekpoints 表示包是否需要保存检查点。它的值是true或false。如果包需要在失败后重启那么这个值要设置为true。
最后一步是配置每一个任务,指定检查点中要包含的内容。这通过FailPackageOnFailure 属性来完成。这个属性要求设置为True,使得检查点中的任务可用。
好了,让我们把这个建起来。打开商业智能开发套件,并启动一个新的集成服务项目。添加两个文件系统任务。创建三个变量用于为两个文本文件保存两个物理路径和一个为目的地保存的路径。如下面所示地命名变量。你可以根据你的文件夹结构改变路径。
SSIS的检查点文件用法
这是假定场景:我们从客户端接收两个文本文件到E:ClientsFiles文件夹下。一个包加载了这些文件并将它们拷贝到目的地(D:FilesReceived)。一旦拷贝了它们,它就提取数据并将其转换到数据库中的相关表中。你的包可能看起来是这样的:
SSIS的检查点文件用法
注意,因为这个样例显示了检查点的执行,转换和转移还没有执行,因此它们用两个脚本任务弹出窗口信息显示“记录成功保存!”来显示。现在创建两个文本文 件Transaction1.txt和Transaction2.txt。不要把它们拷贝到E:ClientsFiles下。现在像下面这样配置系统任 务:
SSIS的检查点文件用法
添加信息到两个脚本任务。现在包做好了。注意我们没有配置任何与检查点相关的东西。首先我们没有设置就运行包,然后了解问题,之后尝试使用检查点解决问题。

在开始之前,让我们确定包在运行。将两个文本文件都放在E:ClientsFiles文件夹下。运行这个包并观察文件是否拷贝到目的地 中和脚本任务的信息是否显示了。它应该是可以的。好了,让我们开始测试这个检查点。从源文件夹下删除Transaction2.txt 并运行它。输出应该如下面所示:
SSIS的检查点文件用法
加载Transaction2文件任务失败,因为没有可用的Transaction2.txt 文件。一旦这个文件可用了我们可以再次运行这个包,但是最大的问题是,它再次运行了第一个任务并再次加载了Transaction1.txt。因此,它可 能导致数据(或业务)错误或冗余(如果转换/转移执行了)。这就是我们所希望避免的,也是我们要使用检查点文件的地方。如果包执行失败了,我们需要从失败 处重启这个包,而不是从头开始。
让我们来进行配置。如下所示地改变属性:
SSIS的检查点文件用法
让我们再次运行这个包。确保源文件夹只包含了Transaction1.txt 文件。就像第一次一样,在第二个任务后包运行失败了。现在打开保存检查点文件的文件夹。你将看到创建了 SamplePackageCheckpoint.xml。之所以创建了这个文件是由于我们将包中的SaveCheckpoints值设置为True。因 为包执行失败所以没有删除这个文件。执行失败是由于加载Transaction2 文件的FailPackageOnFailure 属性设置为True了。
将Tranaction2.txt 文件放置在源文件下并运行这个包。你将看到包从加载Tranaction2文件任务开始并继续执行:
SSIS的检查点文件用法

它从第三个任务开始,因为检查点文件指导它这么做,而包使用了这个检查点文件因为CheckpointUsage属性设置为IfExists了。如果你检查检查点文件所在的文件夹,那你现在不会看到这个文件了。它已经被删除了,因为包执行成功了。
在for loop中的检查点用法
使用for loop 的检查点设置是不同的。我尝试在一个ETL测试应用程序中执行它时遇到了这个问题。为了了解它,让我们试一些简单的代码。
打开一个新的SSIS项目并添加一个For Loop 容器。创建一个叫做Year的变量并设置类型为Int32。设置Year的默认值为2004。假设这样一个场景:你需要从一个给定的年份做一些处理到当前 的年份。所以给定的年份是变量Year 的值。添加一个脚本任务到显示了这个处理的For Loop 容器上。在ScriptTask的ReadOnlyVaribles中添加变量Year,并添加一个信息框,它显示了如下信息:
以下是引用片段:
'code1
MsgBox("Calculationdoneforyear"&Dts.Variables("User::Year").Value.ToString()&".")
Dts.TaskResult=Dts.Results.Success

现在如下所示地配置For Loop 容器。注意我们在InitExpression上不设置@Year 的值。初始值会从变量那里得到。
SSIS的检查点文件用法
完成了!运行这个包。你将看到2004、2005、2006和2007年的信息。现在让我们开始配置检查点文件。如下所示地设置属性:
SSIS的检查点文件用法

因为我们需要在某一点上让包执行失败,所以改变脚本任务的代码,如下所示:
以下是引用片段:
'code2
If(CInt(Dts.Variables("User::Year").Value)=2005)Then
MsgBox("Erroroccurredwhileprocessingfor"&Dts.Variables("User::Year").Value.ToString()&".")
Dts.TaskResult=Dts.Results.Failure
Else
MsgBox("Calculationdoneforyear"&Dts.Variables("User::Year").Value.ToString()&".")
Dts.TaskResult=Dts.Results.Success
EndIf

再次运行这个包。这个包在执行2004年后失败。你将看到检查点文件已经创建了而且没有被删除。改变脚本任务的代码如它原来的样子(代码1)。因为包执 行失败了而有一个检查点文件可用,如果我们重启这个包,它将从失败处开始,它应该开始处理2005。重启这个包。它应该从失败处开始,但是它却是从处理 2004年开始。这是因为检查点文件说失败处的变量Year 是2004,这是错误的。变量Year 的值没有正确地保存。当For Loop 容器中任务的FailPackageOnFailure 属性的值设置为true 时会发生这样的情况。获取For Loop 容器中ScriptTask 的属性并设置FilaPackageOnFailure 为false。删除检查点文件。将ScriptTask 的代码改回代码2。再次运行这个包。
一旦包运行失败,将ScriptTask的代码改回代码1。包应该从失败处开始。检查先前执行所创 建的检查点文件。你将看到变量Year 的值被保存为2005,正如我们所期望的。运行这个包。注意For Loop容器从2005开始计数,如我们所期望的。这里重要的是,我们不应该将For Loop 容器中任务的FailPackageOnFailure 属性设置为True,即使你在里面有另一个For Loop容器(内置的)。

进一步的,我注意到当For Loop 容器包含了不止一个通过优先约束连接的任务时,失败发生后重启的时候,它从失败处开始For Loop容器,但是是从循环中的第一个任务开始而不是从失败的任务开始。这不管配置了怎样的设置都会发生;这证明我们没有控制检查点中for loop的任务的方法。
在事件中的检查点用法
我发现在事件执行上保存检查点也有点不同。而认识到这一点是非常重要 的,因为我们经常编写事件代码。一旦使用一个检查点文件取决于失败点重启了包,它会启动一些事件而另一些则不。让我们配置一个包用于测试。创建一个新的包 并添加一个脚本任务。设置检查点配置如下面所示:
SSIS的检查点文件用法
将下面的代码添加到脚本任务中去。它只是弹出一个信息。
以下是引用片段:
'code1
MsgBox("Scripttaskexecuted!")
Dts.TaskResult=Dts.Results.Success

配置脚本任务中的如下事件。添加一个脚本任务到每一个事件和显示这个事件的适当信息框的代码中去。
SSIS的检查点文件用法
注意,在事件中没有配置与检查点关联的设置。运行这个包用于测试。你将获得按上面的列表定制的信息。“Script task executed”信息将在OnPostValidate和OnInformation 事件之间显示。改变控制流中主要脚本任务的代码。
以下是引用片段:
'code2
MsgBox("Scripttaskfailed!")
Dts.TaskResult=Dts.Results.Failure

这会导致包执行失败。运行包并注意信息。包从OnPreExecute到OnPostValidate显示事件信息、主要的脚本任务信息,然后失败。这 会导致检查点文件仍然保存在文件夹中。如果你通过将代码2替换为代码1来修正错误并再次执行这个包,你将看到任务启动了但一开始的三个事件没有启动。它从 OnInformation事件开始启动事件。记住,即使事件中的脚本任务设置为FailPackageOnFailure = true 这个情况也是会发生的。当你对要执行事件的包使用检查点时要保持谨慎。
其它约束
检查点只能作用于控制流任务。与数据 流相关的任务不能被检查点控制。此外,ForEach Loop 容器也不能被检查点控制。它从头迭代这个循环,而不是从失败处启动。如果你需要从ForEach Loop 里失败任务处开始这个迭代,那么你需要在它上面执行你自己的代码。
你可能在包里包含了一些安全信息。如果使用了检查点,它可能在失败情况下在检查点文件里存储安全信息。因此,最好为检查点文档设置一个所有人都访问不到的安全位置。

souce: http://www.itvue.com/Article/DB/MSSQL/200903/5412.html

BI数据级权限解决方案(zt)

BI数据分析是目前企业的热门应用,而对企业来说,权限控制是非常重要的,尤其是作为决策用的企业报表。目前基于微软SQL Server体 系的BI架构为Integration Services + Analysis Service + Reporting Services,Integration Services和Analysis都属于应用后台的服务,不会在用户前端展现,其权限控制体系不在我们这篇文章的讨论范围内(但是实现数据级权限控制, 需要Analysis Services的参与)。而对于前端展示用的企业报表,权限控制体系分为2种:报表级权限和数据级权限。报表级权限较为简单,主要用于控制谁能够看这个 报表;数据级权限则比较复杂了,任何人看同一张报表,报表上的数据只能是他有权限查看的数据。简单说,就是总经理看到的数据和经理看到的数据是不一样的, 虽然他们在看同一张报表。比较报表级权限和数据级权限,会发现如果实现了数据级权限的控制,那么企业报表是否需要进行权限控制已经不再重要(当然,为了界 面友好性,还是应该控制下的)。
这篇文章主要就是讲述基于SQL Server架构的BI数据级权限的解决方案,这也是我给一个德国大型跨国企业客户实施其BI项目中,对方非常重视的一个功能。这里先简单介绍下这个客户和项目,出于保密要求,我把该客户叫做Customer S(简称CS,呵呵,不是那个游戏哦)。
CS项目前端采用Sharepoint,后台采用SQL Server,主要分析客户S的销售数据。CS的组织结构分为部门、区域;部门和区域是相互交叉的;某个部门的总部人员能够看到全国所有区域的数据;而区域员工则只能看到该区域的数据了。用户能够查看的数据权限,需要在网页上可以进行配置。这就是客户对数据级权限的要求。
针对这些需求,数据级权限解决方案采用如下架构:

BI数据级权限解决方案
报表查看流程说明:
用户查看报表
报表从Cube中获取数据
Cube从数据库中(记录用户的数据权限配置)获得访问用户的权限配置,根据配置返回相应的数据
报表显示结果数据
数据权限配置流程说明:
用户访问数据权限配置页面(由于基于Sharepoint,因此是内嵌数据权限Webpart的Sharepoint页面)
页面获取Cube结构(由于Cube的结构内容很庞大,为了避免网页响应慢,一般通过ajax树状来展示其结构)
用户修改数据权限设置,并且保存到数据库中
说明:这里面进行数据权限控制的对象为域帐号(可以为域用户或者组)。
纵览数据权限实现的这个流程,我们提取出中间几个重要的实现具体讲解解决方案,他们是:
Cube中如何进行权限控制
设置数据权限时,如何读取Cube结构
Cube中如何进行权限控制
SQL Server Analysis Services本身提供了一种设置Cube数据数据权限的机制。打开Analysis Services,我们可以看到“程序集”和“角色”2个条目,他们就是和数据权限设置紧密相关的内容了。如下图所示:
BI数据级权限解决方案
程序集:这是一个DLL类库,通过Visual Studio中新建一个Class Library(类库)来实现。主要作用是返回用户能够访问的Cube数据。
角色:这是访问用户的角色。在这里面可以设置角色的用户,更重要的是设置Cube调用哪个程序集来获取用户能够访问的数据。

我们先来看DataSecurity.dll程序集。这个程序集的代码其实很简单,不会超过30行。其主要流程如下:
1.   读取访问用户的数据权限设置 2.   根据数据权限设置,返回一个能够访问的Dimension数据集MDX字符串
我们看看如下的主要代码(这个类库也就只需要这样一个CS文件):
namespace BI
{
public class DataSecurity
{
public static string GetDimensionSet(string domain_account, string dimension)
// 方法的名字无所谓,参数比较重要
// domain_account:访问用户的帐号,后面我们会知道是从角色的设置中传入
// dimension:是获取哪个维度的数据。在角色里,需要对每一个维度进行设置
{
//return "{[Location].[City].&[Seattle]}", 返回的结果示例
SqlConnection connection = new SqlConnection(connection_string);

connection.Open();

SqlCommand command = new SqlCommand("SP_Security_GetDimensionSetByLoginAccount", connection);

command.CommandType = System.Data.CommandType.StoredProcedure;

SqlParameter p1 = new SqlParameter("@domain_account", domain_account);
SqlParameter p2 = new SqlParameter("@dimension", dimension);

command.Parameters.Add(p1);
command.Parameters.Add(p2);

SqlDataReader reader = command.ExecuteReader();

string result_set = string.Empty;

int count = 0;

while (reader.Read())
{
count++;

if (result_set != string.Empty) result_set += ",";

result_set += (string)reader["DimensionSet"];
}

command.Dispose();

connection.Close();

connection.Dispose();

return "{" + result_set + "}";
}

public DataSecurity()
{
}
}
}


这个类库的作用很简单,抛开BI不谈,其实他就调用了一个存储过 程,把返回结果做了一个字符串拼接,然后返回这个字符串。一般的返回结果会是大致如下:{[Location].[City].& [Seattle]},这表示用户在Location维度下只能够看到Seattle的数据,其他的城市数据都看不到。当然如果是多个城市,那就是用逗号 分隔的列表,比如:{[Location].[City].&[Seattle],[Location].[City].& [Washington]}。
如上所示,字符串拼接很简单,但是这些用户能够访问的具体数据记录在哪呢?这就是用户在网页上设置好数据权限,记录在数据库中的字符串了。
在这里你要更清楚地话,就需要进一步了解MDX,这不在这篇文章的讨论范围之内。
我们首先完成了第一步,结下来就是在角色设置里调用这个DataSecurity.dll类库了。这个比较简单,但是繁琐,对于Cube中的每一个维度都需要手动设置。这个步骤根据如下的示意图走就是了,没有什么代码工作。
BI数据级权限解决方案
打开SecruityRole角色的属性,进入“维度数据”中就可以设置数据权限了。每一个需要控制数据权限的维度和属性都需要设置下,基本上设置为一条语句:
StrtoSet(BI.DataSecurity.GetDimensionSet(USERNAME, "City"))
对这个语句解释下:StrtoSet是将字符串转换为MDX里的数据集。USERNAME是访问者的域帐号,City则为我们自定义的参数,表示要获取City属性维度的授权数据。
到了这里,我们已经完成了很重要的一步,数据权限的主体已经实现了。但是对于用户来说,他需要有一个前端界面来设置这些数据权限。下面的内容就是为了解 决这个问题,不过这里,我只挑出最重要的部分,读取Cube结构来讲,其他的部分你完全可以自己设计。在CS这个项目中,我们是做了如下工作:

所有的设置界面都是Sharepoint Webpart(请参见相关内容)
Webpart中的ajax(这个要单独拿出来说,是因为这个部分比较麻烦),需要用到ajax的原因就是Cube的结构是很大的,如果一次性读出来,肯定是等到花儿也谢了,相信没有人会用他。
后台可以控制哪些维度需要设置数据权限(有些维度不需要设置数据权限,那么就不让他在ajax树中展示出来了)
有自定义的角色,这个角色不同于刚才讲的Cube中的角色。这是用户自己定义的数据权限角色,刚才的角色只需要那一个就足够了。
有了角色自然有搜索、设置用户、设置角色的数据权限、编辑、删除
这个都可以根据你的需要进行设计,不一定要完全相同,就比如我用了ajax树来展示Cube结构,但是你可以采用别的方式。
下面我们就进入下一个重要话题,就是读取Cube的结构(其实在读取这个结构本身,前面的数据权限就已经开始起作用了,没有权限访问的数据不会出现在ajax树中)。
设置数据权限时,如何读取Cube结构
读取Cube的结构,微软已经提供了一套非常丰富的类库给我们。这里就简单介绍下,如果你在具体实现过程中遇到了问题,相信上Google是一个最好的办法。
下面我们介绍读取Cube结构的具体内容,首先就是连上你的Cube。这主要通过如下语句完成。
AdomdConnection adomdConnection = new AdomdConnection();
adomdConnection.ConnectionString = “Data Source=localhost;Catalog=MyCube;”;

adomdConnection.Open();

// 这里读取具体的Cube结构

adomdConnection.Close();
adomdConnection.Dispose();

在连上Cube之后,通过adomdConnection可以读取整个Cube了。主要涉及到如下内容:
Cube:CubeDef cube = adomdConnection.Cubes[“MyCubeName”];
Dimension:cube.Dimensions,这里面是所有的Dimension。
Hierarchy:dimension.Hierarchies,所有的层次
Member:hierarchy.Levels[0].GetMembers(),所有成员
通过以上几个内容就可以把整个Cube的结构完全展现出来,有了他们,就看你怎么展示你的Cube数据了。当然了,首先我们不能忘了添加一个引用:
Microsoft.AnalysisServices.AdomdClient
结束语
到这里为止,我介绍了BI数据权限解决方案中涉及到的最重要的内容,基于这些内容,你可以实现自己的BI数据权限解决方案,并且把它应用到你的项目中去,从而给你的项目添上亮点。
当然了,实现整个解决方案还是需要花费很多时间的,毕竟对用户来说,他们需要一个简单易用的结果。这些友好的界面工作都需要留给你来做。

source: http://www.itvue.com/Article/DB/MSSQL/200903/5534.html

SQL Server调优经历(ZT)

前段时间数据库健康检查发现SQL Server服务器的idle时间变少,IO还是比较空闲,估计是遇到了高CPU占用的语句了。
介绍一下背景,我们公司负责运维N多的应有系统,负责提供良好的软、硬件环境,至于应用的开发质量,我们就无能为力了
解决这个问题,我的思路是:
找出CPU占用最大的语句。
分析查询计划。
优化。
1、找出语句
使用SQL Server自带的性能报表(不是报表服务),找出CPU占用最大的语句。如图1所示
一次SQL Server调优经历
图1 性能报表
我选取了“性能-按总CPU时间排在前面的查询”,得出以下两张报表,如图2所示:
一次SQL Server调优经历
图2 性能-按总CPU时间排在前面的查询
在报表中不能直接把语句Copy出来,非得让我另存为Excel才能Copy语句;而且经常标示不了是语句属于哪个数据库,不爽 :( 。
费了我九牛二虎之力才找出该条语句在哪个数据库执行,然后马上备份数据库,在另一个非生产数据库上面还原,创造实验环境。
废话少说,我把语句Copy出来,顺便整理了一下格式。如下:
select*
fromnetwork_listen
where
node_codein
(
selectdistinctnode_code
fromview_Log_Network_circsByUnit
wherestatus='1'
) 
or
node_code=
(
selecttop1nodeCode
fromTransmissionUnit_LocalInfo
) 
and
node_code<>
(
selectparentNodeCode
fromTransmissionUnit_RouterInfo
wherenodeCode=
(
selecttop1nodeCode
fromTransmissionUnit_LocalInfo
)
)


2、分析语句
执行计划如下:
图太大了,将就着看吧 :( .
一次SQL Server调优经历
图3 查询计划全图
一次SQL Server调优经历
图4 查询计划1
一次SQL Server调优经历
图5 查询计划2
一次SQL Server调优经历
图6 查询计划3
从整个查询计划来看,主要开销都花在了图5的那个部分——两个“聚集索引扫描”。
查看一下这两个数“聚集索引扫描”,搞什么飞机呢?
一次SQL Server调优经历 一次SQL Server调优经历
奇怪了,查询语句里面没有Log_Nwtwork_circs 这个表啊,再仔细分析一下这个执行计划,嫌疑最大的就是view_Log_Network_circsByUnit这个视图了。
查看一下这个试图的定义:
CREATEVIEW[dbo].[view_Log_Network_circsByUnit]
AS
SELECTB.*
FROM(
SELECTnode_code,MAX(end_time)ASend_time
FROMLog_Network_circs
GROUPBYnode_code
)A
LEFTOUTERJOIN
dbo.Log_Network_circsB
ON
A.node_code=B.node_code
AND
A.end_time=B.end_time


看着有点晕是吧,那么看看下图
一次SQL Server调优经历 
3、优化
SQL写得好不好,咱不说,反正我是不能改SQL的,而且应该可以判断出整个查询最耗时的地方就是用在搞这张试图了。
那就只能针对这个试图调优啦。仔细观察这个试图,实际上就涉及到一个表 Log_Network_circs,下面是该表的表结构:
CREATETABLE[dbo].[Log_Network_circs](
[log_id][varchar](30)NOTNULL,
[node_code][varchar](100)NULL,
[node_name][varchar](100)NULL,
[server_name][varchar](100)NULL,
[start_time][datetime]NULL,
[end_time][datetime]NULL,
[status][varchar](30)NULL,
CONSTRAINT[PK_LOG_NETWORK_CIRCS]PRIMARYKEYCLUSTERED
(
[log_id]ASC
)WITH(PAD_INDEX =OFF,STATISTICS_NORECOMPUTE =OFF,IGNORE_DUP_KEY=OFF,ALLOW_ROW_LOCKS =ON,ALLOW_PAGE_LOCKS =ON)ON[PRIMARY]
)ON[PRIMARY]

数据量有489957条记录,不算太大。
根据 3、经常与其他表进行连接的表,在连接字段上应该建立索引;
感觉上得在 node_code 和 end_time 这两字段上建立一个复合索引,大概定义如下:
CREATEINDEX[idx__Log_Network]
ONLog_Network_circs
(
node_codeASC,
end_timeASC
)

保险起见,我把需要调优的语句copy到一个文件里,然后打开“数据库引擎优化顾问”,设置好数据库,得出以下调优结果:

一次SQL Server调优经历
CREATESTATISTICS[_dta_stat_559341057_6_2]ON[dbo].[Log_Network_circs]([end_time],[node_code])
CREATENONCLUSTEREDINDEX[_dta_index_Log_Network_circs_24_559341057__K2_K6]ON[dbo].[Log_Network_circs]
(
[node_code]ASC,
[end_time]ASC
)WITH(SORT_IN_TEMPDB=OFF,IGNORE_DUP_KEY=OFF,DROP_EXISTING=OFF,ONLINE=OFF)ON[PRIMARY]

嗯,结果差不多,具体参数再说。
按照“数据库引擎优化顾问”给出的建议,建立 STATISTICS 和 INDEX 。
再看看优化后的执行计划
一次SQL Server调优经历
明显查询 view_Log_Network_circsByUnit 这个视图的执行计划不一样了。
一次SQL Server调优经历
不看广告,看疗效,使用统计功能。执行以下语句:
SETSTATISTICSIOon;
SETSTATISTICSTIMEon;

(2行受影响)
表'Log_Network_circs'。扫描计数2,逻辑读取13558次,物理读取0次,预读0次,lob逻辑读取0次,lob物理读取0次,lob预读0次。
表'TransmissionUnit_RouterInfo'。扫描计数0,逻辑读取2次,物理读取0次,预读0次,lob逻辑读取0次,lob物理读取0次,lob预读0次。
表'TransmissionUnit_LocalInfo'。扫描计数3,逻辑读取6次,物理读取0次,预读0次,lob逻辑读取0次,lob物理读取0次,lob预读0次。
表'network_listen'。扫描计数1,逻辑读取2次,物理读取0次,预读0次,lob逻辑读取0次,lob物理读取0次,lob预读0次。
SQLServer执行时间:
CPU时间=719毫秒,占用时间=719毫秒。
(2行受影响)
表'Log_Network_circs'。扫描计数2,逻辑读取9次,物理读取0次,预读0次,lob逻辑读取0次,lob物理读取0次,lob预读0次。
表'TransmissionUnit_RouterInfo'。扫描计数0,逻辑读取2次,物理读取0次,预读0次,lob逻辑读取0次,lob物理读取0次,lob预读0次。
表'TransmissionUnit_LocalInfo'。扫描计数3,逻辑读取6次,物理读取0次,预读0次,lob逻辑读取0次,lob物理读取0次,lob预读0次。
表'network_listen'。扫描计数1,逻辑读取2次,物理读取0次,预读0次,lob逻辑读取0次,lob物理读取0次,lob预读0次。
SQLServer执行时间:
CPU时间=0毫秒,占用时间=2毫秒。

逻辑读取数,总执行时间都大大缩减,开来调优还是挺成功的 :) 。