我正在执行以下更新:
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子句中设置这个变量,然后在更新集中使用它,但我想这是不可能的,对吗?
那么我怎样才能获得更好的数据库性能呢?
答案 0 :(得分:2)
您可以使用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;