【问题标题】:Improving performance of adding a column with a single value提高添加具有单个值的列的性能
【发布时间】:2015-04-11 19:59:18
【问题描述】:

通过实验并且令人惊讶的是,我发现在大型表上左连接点表比将单个值简单地分配给列要快得多。点表是指 1x1(1 行 1 列)的表。

方法 1。简单的赋值,我的意思是这个(慢):

SELECT A.*, 'Value' as NewColumn,
FROM Table1 A

方法 2。左连接点表,我的意思是(更快):

WITH B AS (SELECT 'Value' as 'NewColumn')
SELECT * Table1 A
LEFT JOIN B
ON A.ID <> B.NewColumn

现在是我问题的核心。有人可以告诉我如何摆脱整个 ON 子句:

ON A.ID &lt;&gt; B.NewColumn?

检查连接条件似乎是不必要的浪费时间,因为表 A 的键不能等于表 B 的键。如果 t1.ID 的值与 'Value' 相同,它将从结果中丢弃行。删除该条件或可能将 &lt;&gt; 更改为 = 符号,似乎有更多空间来促进连接的性能。

2015 年 2 月 23 日更新
向性能专家提出的赏金问题。我的问答中提到的哪种方法最快。
方法 1 简单赋值,
方法 2 左连接点表,
方法 3 交叉连接积分表(感谢 Gordon Linoff 的回答)
方法 4 在赏金期间可能建议的任何其他方法。
正如我在 3 种方法中以秒为单位测量查询执行的经验时间一样 - 使用 LEFT JOIN 的第二种方法是最快的。然后是 CROSS JOIN 方法,最后是简单的赋值。令人惊讶的是。需要有所罗门之剑的表演专家来确认或否认。

【问题讨论】:

  • 如果这实际上更快,我会感到非常惊讶。这两个查询具有相同的执行计划。但是,是的,戈登是正确的,你想要一个CROSS JOIN
  • 我尝试了 3 种方法 (1) 值 SELECT * 的简单别名,1 AS NewColumn - 这是我调用较慢的解决方案,(2) LEFT JOIN B 在不能满足的条件下,(3 ) 交叉连接。在 41 秒的同一时间内,3 个查询选择了 (1) 177497 行,(2) 234708 行,(3) 198036 行。所以获胜者是 LEFT JOIN。我不确定我是否能够在我的机器上的所有 3 个查询中保持相同的可比情况。尽管如此,这场比赛还是值得专家仲裁者关注的。
  • 也许这是 LEFT JOIN 快速性能的罕见场景,在 dbenham 的回答中描述了 +50 赏金(不是顶部标记为已接受的那个)stackoverflow.com/questions/2726657/…
  • 您给出的示例距离现实世界使用还有很长的路要走,现实世界示例中的性能可能会受到其他因素的影响,例如存储的数据、可能需要的其他连接、索引等。如果您可以显示更多详细信息以及为什么/为什么需要提高性能,它可能会帮助您获得更好的答案。为什么需要为输出中的所有行分配相同的值?是否存在您可能需要该列中的其他值而导致您更改所需连接的情况(这无论如何都会影响您的整个查询计划,使示例无效)?
  • 也许我遗漏了一些明显的东西,但是您的外连接连接标准ON A.ID &lt;&gt; B.NewColumn 会导致数据集中的额外列始终具有 NULL 值,这与原始要求背道而驰?

标签: sql sql-server join


【解决方案1】:

我很惊讶这对于一个简单的表达式来说更快,但你似乎想要一个cross join

WITH B AS (SELECT 'Value' as NewColumn)
SELECT *
FROM Table1 A CROSS JOIN
     B;

我使用此构造将“参数”放入查询中(可以轻松更改的值)。但是,我不明白为什么它会更快。如果表达式比较复杂(比如子查询或者非常复杂的计算),那么这个方法只计算一次。在原始查询中,它通常只会被评估一次,但也可能会针对每一行进行评估。

【讨论】:

    【解决方案2】:

    你也可以试试CROSS APPLY:

    SELECT A.*, B.*,
    FROM Table1 A
    CROSS APPLY(SELECT 'Value' as 'NewColumn') B
    

    【讨论】:

      【解决方案3】:

      你能不能尝试插入临时表而不是输出到屏幕:

      SELECT A.*, 'Value' as NewColumn
      INTO #Table1Assign
      FROM Table1 A
      

      WITH B AS (SELECT 'Value' as 'NewColumn')
      SELECT * Table1 A
      INTO #Table1Join
      LEFT JOIN B
      ON A.ID <> B.NewColumn
      

      这将数据的实际传输和呈现到 SSMS 排除在外,这可能是由于网络速度变慢或客户端处理造成的。

      当我使用 1M 行表运行此程序时,即使我为连接方法切换到 CROSS JOIN,我也始终使用简单的分配方法获得更好的性能。

      【讨论】:

        【解决方案4】:

        我怀疑第二种方法会更快,三个选择和左连接。 首先,您应该使用各种样本数据重复测试相同的查询。

        真实的场景是什么样的?

        内连接肯定比左连接快。

        这个怎么样?

        Declare @t table(id int,c2 varchar(10))
        INSERT INTO @T
        select 1,'A' union all
        select 2,'A' union all
        select 3,'B' union all
        select 4,'B' 
        
        Declare @t1 table(nEWcOL varchar(10))
        INSERT INTO @T1 Values('Value')
        
        -- #Approach1
        --SELECT * FROM @T outer apply
         --@t1
        
        --Create index on both join column
         --#Approach2
        SELECT * FROM @T A inner join
         @t1 b on a.c2<>b.nEWcOL
        
        --#Approach3
        Declare @value varchar(20)
        Select @value= nEWcOL from @t1
        
        select *,@value value from @t
        

        【讨论】:

          【解决方案5】:

          评论的文字太多,所以添加了这个作为答案,尽管我实际上更多地添加到问题中(**)

          不知何故,我认为这将是那些“视情况而定”的情况之一。我认为这在很大程度上取决于所涉及的行数,甚至更多取决于数据之后会发生什么。它是简单地返回,是在GROUP BYDISTINCT 中使用,我们是否进一步JOIN 或用它计算等等。

          无论如何,我认为这 IS 是一个有趣的问题,因为我不得不找出在单行临时表中包含十几个“参数”比将它们预先分配给 12 个变量。很多很多个月前,给我的代码在我看来就像一个荒谬结构,所以我重写了它以使用@variables。这是在一个 +1000 行的存储过程中,需要从中挤出一些额外的性能。经过相当多的重构后,它的运行速度明显比更改前慢?!?!!

          我从来没有真正理解为什么,当时只是再次恢复到旧版本。我最好的猜测是某种奇怪的参数嗅探与(自动创建的?)有关临时表的统计信息的组合;如果有人可以为您的问题带来一些启示,它可能也会导致我的答案 =)

          (**:我意识到 SO 不是一个论坛,所以我先道歉,只是想说明观察到的 OP 行为并不完全是轶事)

          【讨论】:

            【解决方案6】:

            Select * 不能在 SQL 上正确使用索引,您应该始终指定您的列。

            除此之外我会使用

            DECLARE @Value VARCHAR(30) = 'Value'
            SELECT t.Id, t.C2, @Value NewColumn
            FROM Table1 t
            

            【讨论】:

            • 虽然确实选择所有列可能会导致查找,否则可以通过仅从(覆盖)索引中选择您需要的字段来避免这种查找;显式选择所有字段与通过 * 符号隐式选择字段没有任何区别。
            猜你喜欢
            • 2023-02-24
            • 2015-11-17
            • 1970-01-01
            • 2019-05-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-02-07
            相关资源
            最近更新 更多