开篇介绍

在 SSIS Data Flow 中有一个 Multicast 组件,它的作用和 Merge, Merge Join 或者 Union All 等合并数据流组件对比起来作用正好相反。非常直观,它可以将一个数据流平行分开成为多个数据流供下游其它 Data Flow 组件使用。

使用 Multicast Task 的几种情形

第一种,从同一个数据源中取出一部分数据直接放到 A 表中,一部分数据直接放到 B 表中。我曾经遇到一个370多列的一个文件,这370列的文件可以分出列数不等的7,8 张表。我最开始的做法是先将这个文件的数据 Load 到一个大表中,然后再从大表抽取不同的列到小表中,这样相当于形成了二次加载,效率不高,后来使用 Multicast 就可以一次性直接将 370 列宽的文件分散到不同的表中。

第二种,从数据源 A 抽取数据到 B,B 每次都会先 Truncate 一下,但是又需要备份一下每次从 A 抽取的数据,这个时候也可以使用 Multicast。在每次从 A 抽取数据的时候,通过 Multicast 使数据在导向 B 的同时也导向到 B 的备份表。

第三种,类似于第二种,不同的是没有备份表,但是需要保留加载的一些 Audit 信息数据。比如,从 Source 抽取数据到 Staging 的时候,同时需要记录一下抽取的行数,以及用来标示这批 Staging 数据中最大的时间戳,表名和列的名称。这样的话,下次加载数据到 Staging 的时候就只选择加载新增的 Source 数据,也就是上一批最大时间戳之后的新数据。

当然,同一种问题可能有不同的解决的方式,欢迎大家补充!

下面的示例演示一下第一种和第三种情形。

第一种 - 分散同一个 Source 表数据到多个目标表中

先从 TSQL2012 中抽取一部分测试的数据 (TSQL2012 是 Microsoft SQL Server 2012 High-Performance T-SQL Using Window Function 一书中的示例数据库),我们的 Source 表就是 SalesOrderSource。

USE BIWORK_SSIS
GO IF OBJECT_ID('dbo.SalesOrderSource','U') IS NOT NULL
DROP TABLE dbo.SalesOrderSource
GO SELECT *
INTO dbo.SalesOrderSource
FROM TSQL2012.Sales.Orders
WHERE orderdate < '2006-08-01' SELECT * FROM dbo.SalesOrderSource

创建两个目标表,一个用来简单存储 Order 相关信息,一个用来简单存储 Ship 相关信息。

IF OBJECT_ID('dbo.SalesOrder','U') IS NOT NULL
DROP TABLE dbo.SalesOrder IF OBJECT_ID('dbo.OrderShip','U') IS NOT NULL
DROP TABLE dbo.OrderShip CREATE TABLE dbo.SalesOrder
(
OrderID INT,
CustID INT,
EmpID INT,
OrderDate DATETIME,
CreateDate DATETIME DEFAULT(GETDATE())
) CREATE TABLE dbo.OrderShip
(
OrderID INT,
ShippedDate DATETIME,
Shipperid INT,
freight MONEY,
shipname NVARCHAR(40),
CreateDate DATETIME DEFAULT(GETDATE())
)

创建连接管理器的过程就不多说了,新建一个 Data Flow Task, 然后创建一个 OLE DB Source 指向 SalesOrderSource 这张数据源表。

在 Columns 中选择只需要向下输出的列,减少不必要的数据传输。

这时就可以添加 Multicast 组件了,并且同时添加另外两个 OLE DB Destination 组件连接到 Multicast 上。

编辑 OLE_DST_Order

这里的 Avaliable Input 从 数据源经 Multicast 出来的对于 OLE_DST_Order 和 OLE_DST_Ship Task 来说都是等同的,一模一样的。不一样的就是 OLE_DST_Order 可能只需要其中一部分列,而 OLE_DST_Ship 只需要另外的一部分列。

编辑 OLE_DST_Ship

Column Mapping

保存并执行 Package,可以看到一个数据源通过 Multicast 就将数据流分成不同的支流走向其它的 Task,并且支流中的数据也是一模一样的。只不过不同的 Destination Task 做了不同的操作,两个分支数据流的执行也是并行执行的,效率上得到的极大的提升。

查询一下最终输出的结果,同一个数据源的数据分拆到不同的目标表中了。

第二种和第一种类似,略过。

第三种

假设 SalesOrderSource  是数据源表。现在需要从 数据源表加载数据到 Staging 表中,并且同时需要记录一下每次加载数据的条数,以及能够标示 SalesOrderSource 的在当此加载的最大时间戳,这样下次加载的时候就可以判断应该从什么时候开始只加载新增的部分数据了。

这种情况一般会配合 ProcessLogID 来使用,Package 每执行一次就是一个 Process 有 一个 ProcessLogID,并且可以记录成功或者失败的状态。在这个例子中,就不提供 ProcessLog 的流程了,只简单演示一下通过 Multicast 来实现 Audit 信息记录的处理方式。

先看一下这个订单表,每增加一笔订单就会增加一条数据,OrderDate 表示了下单的日期。假设今天是  2006-12-01,每次加载的时候只加载一个月以前的历史数据。如果第一次加载了 OrderDate < 2006-11-01 之前的数据,那么下一个月 2007-01-01 就只应该加载 2006-11-01 至 2006-12-01 之间的所谓增量数据了。这种情况下,时间点很好确定,都是上一个月1日之前的数据。那如果加载周期不固定呢?那么就有必要记录上次加载的最大时间戳,而这里的 OrderDate 列就是记录上次加载最大时间戳的时间依据。

运行下面的 SQL 语句创建相关测试表 -

USE BIWORK_SSIS
GO IF OBJECT_ID('dbo.SalesOrderSource','U') IS NOT NULL
DROP TABLE dbo.SalesOrderSource
GO SELECT *
INTO dbo.SalesOrderSource
FROM TSQL2012.Sales.Orders
WHERE orderdate < '2006-08-01' SELECT * FROM dbo.SalesOrderSource IF OBJECT_ID('dbo.OrderShipStaging','U') IS NOT NULL
DROP TABLE dbo.OrderShipStaging IF OBJECT_ID('dbo.StagingAudit','U') IS NOT NULL
DROP TABLE dbo.StagingAudit CREATE TABLE dbo.OrderShipStaging
(
OrderID INT,
OrderDate DATETIME,
ShippedDate DATETIME,
Shipperid INT,
freight MONEY,
shipname NVARCHAR(40),
CreateDate DATETIME DEFAULT(GETDATE())
) CREATE TABLE dbo.StagingAudit
(
ProcessLogID INT PRIMARY KEY IDENTITY(1,1),
TableName NVARCHAR(50),
TrackColumnName NVARCHAR(50),
TotalCount INT,
LastLoadingDate DATETIME
) SELECT * FROM dbo.StagingAudit
SELECT * FROM dbo.OrderShipStaging

StagingAudit 表可以用来跟踪很多有 Fact 表特征的数据表加载信息,因为类似于 Dimension 信息一般在 Staging 阶段每次都是全部重新加载,数据量本身不大。但是对于有 Fact 事实特征的历史数据,每次都重新加载是非常浪费时间的,所以这些表都是要 Track 的。

StagingAudit 表中的 ProcessLogID 只是用来模拟一下 ProcessLog,实际开发当中还会用到其它的列信息,在这里就都省略了。包括每次加载的时候还有检查上一次加载是否成功,上一次加载的时间戳等检查逻辑在这里也省略掉。

把上一个例子中的 Data Flow Task 复制一份,然后删除掉 Multicast 下 Order Destination 的 Task,新添一个 Aggregate 组,OLE_DST_Ship 中的目标表现在换成 dbo.OrderShipStaging 并重新 Mapping 一下。

这里取到数据流中的行数以及最大的 OrderDate 值。

下面添加一个 Derived Column,写入 Table Name 和 Column Name,如果有 Process 或者其它的表的话,也可以添加其它表的信息。

添加一个 OLE DB Destination 组件,并且配置 StagingAudit 表。

Column Mapping

保存 Package 并执行这个 Data Flow Task,在这里可以看到当从 Source 源抽取数据到 Staging 表的同时,通过 Multicast 并行的将数据流分向 Aggregate 组件进行了信息统计,并且保存到 StagingAudit 表中。

再来看看 StagingAudit 表中的记录。

至此,可以通过上面的几个小示例认识到 Multicast 的作用和特点。

总结

对于上面几个例子中提出的一些解决方案在性能上也有进一步的提升空间,特别是在数据量超过千万级以上应该要好好尝试一下不同的解决方案,哪一种方案在性能上会更好一些。

比如说,之前提到的有关表备份的问题,通过 Multicast 分支平行写入目标表。在我本机的测试过程中(8GB+2.5GHz), 通过 Multicast 平行写入,500W的测试数据大概在30秒 - 50秒左右完成,千万级差不多在90秒内。当数据量超过千万级或者亿级的时候,也可以考虑使用分区表切换分区的方式来进行。

还有就是第三个示例中出现的 Aggregate 组件和 Sort 组件一样是一个 Blocked 组件,非同步组件,它需要将上游数据流全部加载完毕处理完了之后才开发它自身的数据流到下游组件。这样它所在的整个 Data Flow Task 将会一直被阻塞直到它全部处理完成之后才会走向下一个 Data Flow Task。 所以,也可以考虑当 Staging 数据写完之后再来基于 Staging 数据来记录一些统计信息。

关于在上面提到的有关解决方案,需求不同,项目背景不同可能在解决方案的选择上会有一些差别。在性能方面出现的问题,可能与表本身结构,索引相关,与数据源网络传输,与开发环境的配置高低多少,数据量大小都有关系,但是不同解决方案性能上的临界点,高低之分是需要在这些特定环境下不断尝试,优化才能真正选择一个最优的解决方案。

更多 BI 文章请参看 BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)如果觉得这篇文章看了对您有帮助,请帮助推荐,以方便他人在 BIWORK 博客推荐栏中快速看到这些文章

微软BI 之SSIS 系列 - 使用 Multicast Task 将数据同时写入多个目标表,以及写入Audit 与增量处理信息的更多相关文章

  1. 微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件

    原文:微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件 开篇介绍 大多数情况下我们的 SSIS 包都会配置在 SQL Agent ...

  2. 微软BI 之SSIS 系列 - Execute SQL Task 中的 Single Row 与 Full Result Set 的处理技巧

    开篇介绍 Execute SQL Task 这个控件在微软BI ETL 项目中使用的频率还是非常高的,也是大部分入门 SSIS 初学者最早接触到的几个控制流控件. 我们通常使用 Execute SQL ...

  3. 微软BI 之SSIS 系列 - MVP 们也不解的 Scrip Task 脚本任务中的一个 Bug

    开篇介绍 前些天自己在整理 SSIS 2012 资料的时候发现了一个功能设计上的疑似Bug,在 Script Task 中是可以给只读列表中的变量赋值.我记得以前在 2008 的版本中为了弄明白这个配 ...

  4. 微软BI 之SSIS 系列 - 数据仓库中实现 Slowly Changing Dimension 缓慢渐变维度的三种方式

    开篇介绍 关于 Slowly Changing Dimension 缓慢渐变维度的理论概念请参看 数据仓库系列 - 缓慢渐变维度 (Slowly Changing Dimension) 常见的三种类型 ...

  5. 微软BI 之SSIS 系列 - 在 SSIS 中导入 ACCESS 数据库中的数据

    开篇介绍 来自 天善学院 一个学员的问题,如何在 SSIS 中导入 ACCESS 数据表中的数据. 在 SSIS 中导入 ACCESS 数据库数据 ACCESS 实际上是一个轻量级的桌面数据库,直接使 ...

  6. 微软BI 之SSIS 系列 - 使用 Script Component Destination 和 ADO.NET 解析不规则文件并插入数据

    开篇介绍 这一篇文章是 微软BI 之SSIS 系列 - 带有 Header 和 Trailer 的不规则的平面文件输出处理技巧 的续篇,在上篇文章中介绍到了对于这种不规则文件输出的处理方式.比如下图中 ...

  7. 微软BI 之SSIS 系列 - Lookup 中的字符串比较大小写处理 Case Sensitive or Insensitive

    开篇介绍 前几天碰到这样的一个问题,在 Lookup 中如何设置大小写不敏感比较,即如何在 Lookup 中的字符串比较时不区分大小写? 实际上就这个问题已经有很多人提给微软了,但是得到的结果就是 C ...

  8. 微软BI 之SSIS 系列 - 再谈Lookup 缓存

    开篇介绍 关于 Lookup 的缓存其实在之前的一篇文章中已经提到了 微软BI 之SSIS 系列 - Lookup 组件的使用与它的几种缓存模式 - Full Cache, Partial Cache ...

  9. 微软BI 之SSIS 系列 - 带有 Header 和 Trailer 的不规则的平面文件输出处理技巧

    案例背景与需求介绍 之前做过一个美国的医疗保险的项目,保险提供商有大量的文件需要发送给比如像银行,医疗协会,第三方服务商等.比如像与银行交互的 ACH 文件,传送给协会的 ACH Credit 等文件 ...

随机推荐

  1. 用PNChart绘制饼状图简介

    写在前面 最近做的小Demo中有一个绘制饼状图的需求.在开始实现之前上网了解了一下现有的一些绘制图形的第三方库,相应的库还是有挺多的,PNChart便是其中一个.PNChart是一个90后的中国boy ...

  2. python 全栈开发,Day85(Git补充,随机生成图片验证码)

    昨日内容回顾 第一部分:django相关 1.django请求生命周期 1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端 请求头和请求体中会包含浏览器的动作(action),这 ...

  3. MVC常用筛选器Filter

    1.ActionFilterAttribute using System; using System.Collections.Generic; using System.Diagnostics; us ...

  4. memcache的简单使用示例

    在实际应用中我们会缓存从数据库中查出来的结果集,以md5($sql)为$key,结果集为值. 以只是在php简单应用代码: <?php //建立memcache链接 $memcache = ne ...

  5. BZOJ1303 [CQOI2009]中位数图 其他

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1303 题意概括 给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b.中位数 ...

  6. Spring日记_01 之 Eclipse下的Tomcat服务器配置 以及 Springmvc和Servlet的使用

    安装Tomcat – window – preferences – Server                                                  右键Tomcat v ...

  7. cookie和session、

    https://my.oschina.net/yoyo1987/blog/156117 Session会在浏览器关闭后消失吗? 通常情况下,当我们关闭浏览器再重新打开后,我们就需要再次进行登陆(如果没 ...

  8. Java 泛型优点之编译时类型检查

    Java 泛型优点之编译时类型检查 使用泛型代码要比非泛型代码更有优势,下面是 Java 官方教程对泛型其中一个优点的介绍: "Stronger type checks at compile ...

  9. 两类传输协议:TCP,UDP

    1) TCP是Transfer Control Protocol的简称,是一种面向连接的保证可靠传输的协议.通过TCP协议传输,得到的是一个顺序的无差错的数据流.发送方和接收方的成对的两个socket ...

  10. CF1039C.Network Safety

    目录 题目链接 题解 代码 题目链接 CF1039C.Network Safety 题解 对于一对相邻点,^异或后相同的值唯一a_i ^ t= b_i,a_i ^ b_i = t 对于不在t集合的直接 ...