【发布时间】:2011-10-07 19:44:06
【问题描述】:
您好,我是 SSIS 包的新手,我在编写包并同时阅读它们。
我需要将 DTS 转换为 SSIS 包,并且需要对来自不同数据库的两个源执行联接,并且想知道使用查找联接还是合并联接更好的方法是什么?
从表面上看,它们看起来非常相似。 “合并连接”要求事先对数据进行排序,而“查找”则不需要。任何建议都会非常有帮助。谢谢。
【问题讨论】:
标签: sql-server ssis
您好,我是 SSIS 包的新手,我在编写包并同时阅读它们。
我需要将 DTS 转换为 SSIS 包,并且需要对来自不同数据库的两个源执行联接,并且想知道使用查找联接还是合并联接更好的方法是什么?
从表面上看,它们看起来非常相似。 “合并连接”要求事先对数据进行排序,而“查找”则不需要。任何建议都会非常有帮助。谢谢。
【问题讨论】:
标签: sql-server ssis
屏幕截图 #1 显示了几个可以区分 Merge Join transformation 和 Lookup transformation 的点。
关于查找:
如果您想根据源 1 输入查找源 2 中匹配的行,并且如果您知道每个输入行只有一个匹配项,那么我建议使用查找操作。一个例子是你OrderDetails 表并且你想找到匹配的Order Id 和Customer Number,那么查找是一个更好的选择。
关于合并加入:
如果您想执行联接,例如从Address 表中为Customer 表中的给定客户获取所有地址(家庭、工作、其他),那么您必须使用合并联接,因为客户可以拥有 1或更多与其相关联的地址。
一个比较的例子:
这是一个演示Merge Join 和Lookup 之间性能差异的场景。这里使用的数据是一对一的连接,这是它们之间唯一可以比较的共同场景。
我有三个名为dbo.ItemPriceInfo、dbo.ItemDiscountInfo 和dbo.ItemAmount 的表。 SQL 脚本部分提供了为这些表创建脚本。
Tablesdbo.ItemPriceInfo 和 dbo.ItemDiscountInfo 都有 13,349,729 行。这两个表都将 ItemNumber 作为公共列。 ItemPriceInfo 有价格信息,ItemDiscountInfo 有折扣信息。屏幕截图 #2 显示了每个表中的行数。屏幕截图 #3 显示了前 6 行,以便了解表中存在的数据。
我创建了两个 SSIS 包来比较 Merge Join 和 Lookup 转换的性能。两个包都需要从表dbo.ItemPriceInfo和dbo.ItemDiscountInfo中获取信息,计算总量并保存到表dbo.ItemAmount中。
第一个包使用Merge Join 转换,在里面它使用INNER JOIN 来组合数据。屏幕截图 #4 和 #5 显示了示例包执行和执行持续时间。执行基于 Merge Join 转换的包需要 05 分钟 14 秒 719 毫秒。
第二个包使用了Lookup 转换和完整缓存(这是默认设置)。截图 #6 和 #7 显示了示例包执行和执行持续时间。执行基于查找转换的包需要 11 分钟 03 秒 610 毫秒。您可能会遇到警告消息 Information: The buffer manager has allocated nnnnn bytes, even though the memory pressure has been detected and repeated attempts to swap buffers have failed. Here is a link 讨论如何计算查找缓存大小。在这个包执行过程中,尽管数据流任务完成得更快,但管道清理需要很多时间。
这并不意味着查找转换不好。只是必须明智地使用它。我在我的项目中经常使用它,但我也不会每天处理 10+ 百万行进行查找。通常,我的作业处理 2 到 3 百万行,因此性能非常好。多达 1000 万行,两者表现同样出色。大多数时候,我注意到瓶颈是目标组件而不是转换。您可以通过拥有多个目的地来克服这一点。 Here 是一个示例,展示了多个目的地的实现。
屏幕截图 #8 显示了所有三个表中的记录数。屏幕截图 #9 显示了每个表中的前 6 条记录。
希望对您有所帮助。
SQL 脚本:
CREATE TABLE [dbo].[ItemAmount](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ItemNumber] [nvarchar](30) NOT NULL,
[Price] [numeric](18, 2) NOT NULL,
[Discount] [numeric](18, 2) NOT NULL,
[CalculatedAmount] [numeric](18, 2) NOT NULL,
CONSTRAINT [PK_ItemAmount] PRIMARY KEY CLUSTERED ([Id] ASC)) ON [PRIMARY]
GO
CREATE TABLE [dbo].[ItemDiscountInfo](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ItemNumber] [nvarchar](30) NOT NULL,
[Discount] [numeric](18, 2) NOT NULL,
CONSTRAINT [PK_ItemDiscountInfo] PRIMARY KEY CLUSTERED ([Id] ASC)) ON [PRIMARY]
GO
CREATE TABLE [dbo].[ItemPriceInfo](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ItemNumber] [nvarchar](30) NOT NULL,
[Price] [numeric](18, 2) NOT NULL,
CONSTRAINT [PK_ItemPriceInfo] PRIMARY KEY CLUSTERED ([Id] ASC)) ON [PRIMARY]
GO
屏幕截图 #1:
屏幕截图 #2:
截图#3:
屏幕截图 #4:
屏幕截图 #5:
屏幕截图 #6:
截图#7:
截图#8:
屏幕截图 #9:
【讨论】:
Merge Join 旨在产生类似于 JOIN 在 SQL 中的工作方式的结果。 Lookup 组件不像 SQL JOIN 那样工作。这是一个结果会有所不同的示例。
如果您在输入 1(例如,发票)和输入 2(例如,发票行项目)之间存在一对多关系,您希望这两个输入的组合结果包含一行或多行一张发票。
使用合并连接,您将获得所需的输出。使用查找,其中输入 2 是查找源,输出将是每张发票一行,无论输入 2 中存在多少行。我不记得数据来自输入 2 的哪一行,但我我很确定您至少会收到重复数据警告。
因此,每个组件在 SSIS 中都有自己的角色。
【讨论】:
我会建议考虑第三种选择。您的 OLE DBSource 可能包含查询而不是表,您可以在那里进行连接。这在所有情况下都不好,但是当您可以使用它时,您不必事先进行排序。
【讨论】:
Lookup 类似于 Merge Join 组件中的左连接。 Merge 可以进行其他类型的连接,但如果这是您想要的,区别主要在于性能和便利性。
根据要查找的相对数据量(查找组件的输入)和引用数据量(查找缓存或查找数据源大小),它们的性能特征可能会有很大差异。
例如如果您只需要查找 10 行,但引用的数据集是 1000 万行 - 使用部分缓存或无缓存模式查找会更快,因为它只会获取 10 条记录,而不是 1000 万行。如果您需要查找 1000 万行,并且引用的数据集是 10 行 - 完全缓存的查找可能更快(除非这 1000 万行已经排序并且您可以尝试合并连接)。如果两个数据集都很大(尤其是在超过可用 RAM 的情况下)或较大的一个已排序 - 合并可能是更好的选择。
【讨论】:
有两个区别:
排序:
数据库查询负载:
这会导致: 如果不努力生成排序列表,并且您想要超过大约 1% 的行(单行选择是流式传输时同一行成本的 100 倍左右)(您不想对 1000 万行进行排序内存中的表..)然后合并连接是要走的路。
如果您只期望少量匹配(在启用缓存时查找不同的值),那么查找会更好。
对我来说,两者之间的权衡是需要查找 10k 到 100k 行。
哪个更快取决于
【讨论】:
Merge Join 允许您根据一个或多个条件连接到多个列,而 Lookup 受到更多限制,因为它仅根据某些匹配的列信息获取一个或多个值 - 查找查询将是为数据源中的每个值运行(尽管如果可以,SSIS 会缓存数据源)。
这实际上取决于您的两个数据源包含什么以及您希望最终源如何处理合并。您能否提供有关 DTS 包中架构的更多详细信息?
要考虑的另一件事是性能。如果使用不当,每个都可能比另一个慢,但同样,这将取决于您拥有的数据量和数据源架构。
【讨论】:
我知道这是一个老问题,但我认为给出的答案没有涵盖的一个关键点是,因为合并连接正在合并两个数据流,它可以合并来自任何来源的数据。而对于查找,一个数据源必须保存在 OLE DB 中。
【讨论】: