【问题标题】:SQL SERVER - Set variable in WHERE clauseSQL SERVER - 在 WHERE 子句中设置变量
【发布时间】:2017-01-25 08:54:21
【问题描述】:

我正在执行以下更新:

UPDATE MyTable
SET    Field1 = 0       
FROM   MyTable INNER JOIN AnotherTable
       ON MyTable.ID = AnotherTable.ID
WHERE  0=MyFunc(MyTable.ID)

MyFunc 是一个返回 int 值的函数。

但现在我正在尝试使用 MyFunc 返回的值来更新表 MyTable 上的另一个字段。

UPDATE MyTable
SET    Field1 = 0,
       Field2 = CASE WHEN MyFunc(MyTable.ID) = 0 THEN 'OK' ELSE 'NOK' END
FROM   MyTable INNER JOIN AnotherTable
       ON MyTable.ID = AnotherTable.ID
WHERE  0=MyFunc(MyTable.ID)

这里的问题是我调用了两次函数 MyFunc,一个在 SET 中,一个在 WHERE 子句中,然后我担心性能。

我想知道是否还有其他方法可以做到这一点。我考虑过使用变量,我的意思是,在 WHERE 子句中设置这个变量,然后在更新的集合中使用它,但我想这是不可能的,对吧?

那么我该如何做才能获得更好的数据库性能呢?

【问题讨论】:

  • 好吧...如果您的 WHERE 将其限制为 MyFunc=0;案例陈述的意义何在?
  • 如果 MyFunc 是确定性的,优化器可能足够聪明,每行只调用一次。但在做任何事情之前 - 性能实际上是一个问题吗?您是否设置了性能目标,这段代码目前是否没有达到这些目标?
  • @TZHX Field2 在我的真实案例中对应于一个审计字段(一个时间戳),所以我需要根据这个函数的值是否更新它。如果 MyFunc 返回 0,我需要更新该字段,Field2(带有当前时间戳)以及 Field1(到 0),但是如果 MyFunc 返回的不是 0,我不想更新 Field2,只更新 Field1。
  • 恐怕这不是你的代码所达到的。在你开始担心性能之前,先做一些有效的东西。
  • @TZHX 上面的代码有效,但这不是我的真实情况,我在这里发布了一个示例,使用字符串而不是时间戳,但我认为想法是一样的。

标签: sql-server sql-server-2008 sql-server-2008-r2 sql-update


【解决方案1】:

您可以使用CROSS APPLY 来模拟变量。以下SELECT 将能够使用变量名 FuncResult 处理函数的结果。

SELECT MyTable.Field1 
      ,MyTable.Field2
      ,x.FuncResult
FROM  MyTable 
CROSS APPLY(SELECT dbo.MyFunc(MyTable.ID) AS FuncResult) AS x
INNER JOIN AnotherTable
       ON MyTable.ID = AnotherTable.ID
WHERE FuncResult=0

此外,您还可以查看可更新的 CTE,如下所示:

WITH UpdateableCTE AS
(
    SELECT MyTable.Field1 
          ,MyTable.Field2
          ,x.FuncResult
    FROM  MyTable 
    CROSS APPLY(SELECT dbo.MyFunc(MyTable.ID) AS FuncResult) AS x
    INNER JOIN AnotherTable
           ON MyTable.ID = AnotherTable.ID
    WHERE FuncResult=0
)
UPDATE UpdateableCTE
SET Field1=0
   ,Field2=CASE WHEN FuncResult = 0 /*senseless, as your where clause filters to only this value!*/ THEN 'OK' ELSE 'NOK' END

但是 - 老实说 - 整个问题看起来像开始在二楼盖房子...我很确定,引擎足够聪明,可以计算函数的结果并使用相同的输入重复使用它(至少每行)。

如果你真的很在意性能避免使用标量函数。如果您需要一个函数,内联表值函数,它可能只返回一行中的列,速度要快得多。

更新

这里是 INLINED tabe value function 的示例(单语句,ad-hoc,没有 BEGIN...END):

CREATE FUNCTION dbo.TestInlineTVF(@input INT)
RETURNS TABLE
AS
RETURN SELECT @input*2 AS FuncResult;
GO

DECLARE @tbl TABLE(ID INT IDENTITY,SomeValue VARCHAR(100));
INSERT INTO @tbl VALUES('Row 1'),('Row 2');

SELECT *
FROM @tbl AS t
CROSS APPLY dbo.TestInlineTVF(t.ID) AS x
GO
DROP FUNCTION dbo.TestInlineTVF;

【讨论】:

  • 你最后说的使用内联表值函数看起来很有趣,所以你能提供一个例子吗?我不是数据库专家,非常抱歉。
猜你喜欢
  • 1970-01-01
  • 2016-12-06
  • 2020-06-11
  • 1970-01-01
  • 2020-04-16
  • 1970-01-01
  • 1970-01-01
  • 2021-08-09
  • 1970-01-01
相关资源
最近更新 更多