【问题标题】:What are the differences between Merge Join and Lookup transformations in SSIS?SSIS 中的 Merge Join 和 Lookup 转换有什么区别?
【发布时间】:2011-10-07 19:44:06
【问题描述】:

您好,我是 SSIS 包的新手,我在编写包并同时阅读它们。

我需要将 DTS 转换为 SSIS 包,并且需要对来自不同数据库的两个源执行联接,并且想知道使用查找联接还是合并联接更好的方法是什么?

从表面上看,它们看起来非常相似。 “合并连接”要求事先对数据进行排序,而“查找”则不需要。任何建议都会非常有帮助。谢谢。

【问题讨论】:

    标签: sql-server ssis


    【解决方案1】:

    屏幕截图 #1 显示了几个可以区分 Merge Join transformationLookup transformation 的点。

    关于查找:

    如果您想根据源 1 输入查找源 2 中匹配的行,并且如果您知道每个输入行只有一个匹配项,那么我建议使用查找操作。一个例子是你OrderDetails 表并且你想找到匹配的Order IdCustomer Number,那么查找是一个更好的选择。

    关于合并加入:

    如果您想执行联接,例如从Address 表中为Customer 表中的给定客户获取所有地址(家庭、工作、其他),那么您必须使用合并联接,因为客户可以拥有 1或更多与其相关联的地址。

    一个比较的例子:

    这是一个演示Merge JoinLookup 之间性能差异的场景。这里使用的数据是一对一的连接,这是它们之间唯一可以比较的共同场景。

    1. 我有三个名为dbo.ItemPriceInfodbo.ItemDiscountInfodbo.ItemAmount 的表。 SQL 脚本部分提供了为这些表创建脚本。

    2. Tablesdbo.ItemPriceInfodbo.ItemDiscountInfo 都有 13,349,729 行。这两个表都将 ItemNumber 作为公共列。 ItemPriceInfo 有价格信息,ItemDiscountInfo 有折扣信息。屏幕截图 #2 显示了每个表中的行数。屏幕截图 #3 显示了前 6 行,以便了解表中存在的数据。

    3. 我创建了两个 SSIS 包来比较 Merge Join 和 Lookup 转换的性能。两个包都需要从表dbo.ItemPriceInfodbo.ItemDiscountInfo中获取信息,计算总量并保存到表dbo.ItemAmount中。

    4. 第一个包使用Merge Join 转换,在里面它使用INNER JOIN 来组合数据。屏幕截图 #4 和 #5 显示了示例包执行和执行持续时间。执行基于 Merge Join 转换的包需要 05 分钟 14719 毫秒。

      李>
    5. 第二个包使用了Lookup 转换和完整缓存(这是默认设置)。截图 #6 和 #7 显示了示例包执行和执行持续时间。执行基于查找转换的包需要 11 分钟 03610 毫秒。您可能会遇到警告消息 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 讨论如何计算查找缓存大小。在这个包执行过程中,尽管数据流任务完成得更快,但管道清理需要很多时间。

    6. 并不意味着查找转换不好。只是必须明智地使用它。我在我的项目中经常使用它,但我也不会每天处理 10+ 百万行进行查找。通常,我的作业处理 2 到 3 百万行,因此性能非常好。多达 1000 万行,两者表现同样出色。大多数时候,我注意到瓶颈是目标组件而不是转换。您可以通过拥有多个目的地来克服这一点。 Here 是一个示例,展示了多个目的地的实现。

    7. 屏幕截图 #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:

    【讨论】:

    • 感谢非常全面的回答
    • 太漂亮了。如果我能做到这一点,我会给你更多的分数。
    • 很好的解释。虽然我检查的很晚,但它很棒。
    【解决方案2】:

    Merge Join 旨在产生类似于 JOIN 在 SQL 中的工作方式的结果。 Lookup 组件不像 SQL JOIN 那样工作。这是一个结果会有所不同的示例。

    如果您在输入 1(例如,发票)和输入 2(例如,发票行项目)之间存在一对多关系,您希望这两个输入的组合结果包含一行或多行一张发票。

    使用合并连接,您将获得所需的输出。使用查找,其中输入 2 是查找源,输出将是每张发票一行,无论输入 2 中存在多少行。我不记得数据来自输入 2 的哪一行,但我我很确定您至少会收到重复数据警告。

    因此,每个组件在 SSIS 中都有自己的角色。

    【讨论】:

      【解决方案3】:

      我会建议考虑第三种选择。您的 OLE DBSource 可能包含查询而不是表,您可以在那里进行连接。这在所有情况下都不好,但是当您可以使用它时,您不必事先进行排序。

      【讨论】:

        【解决方案4】:

        Lookup 类似于 Merge Join 组件中的左连接。 Merge 可以进行其他类型的连接,但如果这是您想要的,区别主要在于性能和便利性。

        根据要查找的相对数据量(查找组件的输入)和引用数据量(查找缓存或查找数据源大小),它们的性能特征可能会有很大差异。

        例如如果您只需要查找 10 行,但引用的数据集是 1000 万行 - 使用部分缓存或无缓存模式查找会更快,因为它只会获取 10 条记录,而不是 1000 万行。如果您需要查找 1000 万行,并且引用的数据集是 10 行 - 完全缓存的查找可能更快(除非这 1000 万行已经排序并且您可以尝试合并连接)。如果两个数据集都很大(尤其是在超过可用 RAM 的情况下)或较大的一个已排序 - 合并可能是更好的选择。

        【讨论】:

        • 我发现 Left Join Merge 对于大型比较(例如复制)的性能要好得多
        【解决方案5】:

        有两个区别:

        1. 排序:

          • 合并连接要求两个输入以相同的方式排序
          • 查找不需要对任一输入进行排序。
        2. 数据库查询负载:

          • 合并连接不引用数据库,仅引用 2 个输入流(尽管引用数据通常采用“select * from table order by join critera”的形式)
          • lookup 将为每个被要求加入的(不同的,如果缓存的)值发出 1 个查询。这很快变得比上述选择更昂贵。

        这会导致: 如果不努力生成排序列表,并且您想要超过大约 1% 的行(单行选择是流式传输时同一行成本的 100 倍左右)(您不想对 1000 万行进行排序内存中的表..)然后合并连接是要走的路。

        如果您只期望少量匹配(在启用缓存时查找不同的值),那么查找会更好。

        对我来说,两者之间的权衡是需要查找 10k 到 100k 行。

        哪个更快取决于

        • 要处理的总行数。 (如果表是内存驻留的,那么合并它的一种数据很便宜)
        • 预期的重复查找次数。 (每行的查找开销很高)
        • 如果可以选择排序数据(注意,文本排序受代码排序影响,所以要注意sql认为已排序,ssis也认为已排序)
        • 您将查找整个表格的百分比。 (合并需要选择每一行,如果一侧只有几行,查找会更好)
        • 行的宽度(每页的行数会强烈影响进行单次查找与扫描的 io 成本)(窄行 -> 更倾向于合并)
        • 磁盘上数据的顺序(易于生成排序输出,更喜欢合并,如果您可以按物理磁盘顺序组织查找,则查找成本较低,因为缓存未命中率较低)
        • ssis 服务器和目标之间的网络延迟(更大的延迟 -> 首选合并)
        • 您希望花费多少编码工作(合并编写起来有点复杂)
        • 输入数据的整理——SSIS 合并对包含非字母数字字符但不是 nvarchar 的文本字符串的排序有一些奇怪的想法。 (这用于排序,让 sql 发出 ssis 乐于合并的排序很难)

        【讨论】:

          【解决方案6】:

          Merge Join 允许您根据一个或多个条件连接到多个列,而 Lookup 受到更多限制,因为它仅根据某些匹配的列信息获取一个或多个值 - 查找查询将是为数据源中的每个值运行(尽管如果可以,SSIS 会缓存数据源)。

          这实际上取决于您的两个数据源包含什么以及您希望最终源如何处理合并。您能否提供有关 DTS 包中架构的更多详细信息?

          要考虑的另一件事是性能。如果使用不当,每个都可能比另一个慢,但同样,这将取决于您拥有的数据量和数据源架构。

          【讨论】:

          • @John:谢谢,我会解决的。
          • 您的修复是一种改进,但如果您至少能展示一下 Lookup 的局限性,我真的更喜欢。您知道,在 SSIS 2008 中,您可以从源自缓存转换的缓存连接中提供查找,因此您对输入数据的限制确实很少。
          • 如果我的源和目标数据包含 2000 万条记录,并且我想对从源到目标的每条记录执行匹配(尽管目标中的源只有 1 个匹配)我可以得到内存异常在这种情况下?
          【解决方案7】:

          我知道这是一个老问题,但我认为给出的答案没有涵盖的一个关键点是,因为合并连接正在合并两个数据流,它可以合并来自任何来源的数据。而对于查找,一个数据源必须保存在 OLE DB 中。

          【讨论】:

            猜你喜欢
            • 2014-05-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-07-16
            • 2012-02-22
            相关资源
            最近更新 更多