微软BI 之SSIS 系列 - 使用 Multicast Task 将数据同时写入多个目标表,以及写入Audit 与增量处理信息
开篇介绍
在 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 与增量处理信息的更多相关文章
- 微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件
原文:微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件 开篇介绍 大多数情况下我们的 SSIS 包都会配置在 SQL Agent ...
- 微软BI 之SSIS 系列 - Execute SQL Task 中的 Single Row 与 Full Result Set 的处理技巧
开篇介绍 Execute SQL Task 这个控件在微软BI ETL 项目中使用的频率还是非常高的,也是大部分入门 SSIS 初学者最早接触到的几个控制流控件. 我们通常使用 Execute SQL ...
- 微软BI 之SSIS 系列 - MVP 们也不解的 Scrip Task 脚本任务中的一个 Bug
开篇介绍 前些天自己在整理 SSIS 2012 资料的时候发现了一个功能设计上的疑似Bug,在 Script Task 中是可以给只读列表中的变量赋值.我记得以前在 2008 的版本中为了弄明白这个配 ...
- 微软BI 之SSIS 系列 - 数据仓库中实现 Slowly Changing Dimension 缓慢渐变维度的三种方式
开篇介绍 关于 Slowly Changing Dimension 缓慢渐变维度的理论概念请参看 数据仓库系列 - 缓慢渐变维度 (Slowly Changing Dimension) 常见的三种类型 ...
- 微软BI 之SSIS 系列 - 在 SSIS 中导入 ACCESS 数据库中的数据
开篇介绍 来自 天善学院 一个学员的问题,如何在 SSIS 中导入 ACCESS 数据表中的数据. 在 SSIS 中导入 ACCESS 数据库数据 ACCESS 实际上是一个轻量级的桌面数据库,直接使 ...
- 微软BI 之SSIS 系列 - 使用 Script Component Destination 和 ADO.NET 解析不规则文件并插入数据
开篇介绍 这一篇文章是 微软BI 之SSIS 系列 - 带有 Header 和 Trailer 的不规则的平面文件输出处理技巧 的续篇,在上篇文章中介绍到了对于这种不规则文件输出的处理方式.比如下图中 ...
- 微软BI 之SSIS 系列 - Lookup 中的字符串比较大小写处理 Case Sensitive or Insensitive
开篇介绍 前几天碰到这样的一个问题,在 Lookup 中如何设置大小写不敏感比较,即如何在 Lookup 中的字符串比较时不区分大小写? 实际上就这个问题已经有很多人提给微软了,但是得到的结果就是 C ...
- 微软BI 之SSIS 系列 - 再谈Lookup 缓存
开篇介绍 关于 Lookup 的缓存其实在之前的一篇文章中已经提到了 微软BI 之SSIS 系列 - Lookup 组件的使用与它的几种缓存模式 - Full Cache, Partial Cache ...
- 微软BI 之SSIS 系列 - 带有 Header 和 Trailer 的不规则的平面文件输出处理技巧
案例背景与需求介绍 之前做过一个美国的医疗保险的项目,保险提供商有大量的文件需要发送给比如像银行,医疗协会,第三方服务商等.比如像与银行交互的 ACH 文件,传送给协会的 ACH Credit 等文件 ...
随机推荐
- Gym100340 线性dp
//看题解写的 https://blog.csdn.net/sdfzyhx/article/details/51804748#include<bits/stdc++.h> using na ...
- python 全栈开发,Day88(csrf_exempt,ES6 快速入门,Vue)
BBS项目内容回顾 1. 登陆页面 1. 验证码 1. PIL(Pillow) 2. io 2. ORM 1. 增删改查 3. AJAX $.ajax({ url: '', type: '', dat ...
- oracle表分区创建
一.什么是分区表表分区有以下优点: 1.数据查询:数据被存储到多个文件上,减少了I/O负载,查询速度提高. 2.数据修剪:保存历史数据非常的理想. 3.备份:将大表的数据分成多个文件,方便备份和恢复. ...
- JQuery动画详解(四)
一:基本动画show()显示隐藏的匹配元素.这个就是 'show( speed, [callback] )' 无动画的版本.如果选择的元素是可见的,这个方法将不会改变任何东西.无论这个元素是通过hid ...
- ASP.NET Core 2 学习笔记(九)模型绑定
ASP.NET Core MVC的Model Binding会将HTTP Request数据,以映射的方式对应到参数中.基本上跟ASP.NET MVC差不多,但能Binding的来源更多了一些.本篇将 ...
- C# 关键字const与readonly的区别
尽管你写了很多年的C#的代码,但是可能当别人问到你const与readonly的区别时候,还是会小小的愣一会吧~ 笔者也是在看欧立奇版的<.Net 程序员面试宝典>的时候,才发现自己长久以 ...
- openstack安装-计算节点-nova计算服务安装
一.基础服务安装 先安装基础工具 yum install net-tools vim telnet wget lrzsz 1.添加hosts解析 cat << EOF >/etc/h ...
- BZOJ1042 [HAOI2008]硬币购物 完全背包 容斥原理
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1042 题目概括 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了t ...
- See you~ HDU1892
一开始还离散化弄了好久 离散化细节弄得好差 这题用二维树状数组做很快 因为树状数组下标不为0 所以所有下标要加一处理 还有就是算矩阵的时候要处理两个坐标的大小关系 个人感觉树状数组用for语句写 ...
- Python6 - 函数总结
一.函数的基本知识 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 减少重复代码 使程序变的可扩展 使程序变得易维护 1.1函数定义规则 ...