with子句执行顺序

时间:2016-03-17 11:50:49

标签: sql sql-server

在一个简化的场景中,我的表格 T 看起来像:

Key  Value
1    NULL
1    NULL
1    NULL
2    NULL
2    NULL
3    NULL
3    NULL

我还有一个非常耗时的功能 Foo(Key),必须将其视为黑盒子(我必须使用它,我无法更改它)。

我想更新表格 T ,但要比

更有效
UPDATE T SET Value = dbo.Foo(Key)

基本上我只会为每个执行 Foo 一次。

我试过像

这样的东西
WITH Tmp1 AS
(
   SELECT DISTINCT Key FROM T
)
, Tmp2 AS
(
   SELECT Key, Foo(Key) Value FROM Tmp1
)
UPDATE T
SET T.Value = Tmp2.Value
FROM T JOIN Tmp2 ON T.Key = Tmp2.Key

但意外的是计算时间根本没有变化,因为Sql Server似乎在每一行都再次运行 Foo

有没有其他临时表解决这个问题的想法?

2 个答案:

答案 0 :(得分:2)

一种方法是使用临时表。您无法控制SQL Server如何优化其查询。

如果您不想要临时表,可以进行两次更新:

with toupdate as (
      select t.*, row_number() over (partition by id order by id) as seqnum
      from t
     )
update toupdate
    set value = db.foo(key)
    where seqnum = 1;

然后您可以再次运行类似的更新:

with toupdate as (
      select t.*, max(value) over (partition by id) as as keyvalue
      from t
     )
update toupdate
    set value = keyvalue
    where value is null;

答案 1 :(得分:0)

您可以这样尝试:

CREATE FUNCTION dbo.Foo(@TheKey INT) 
RETURNS INT 
AS 
BEGIN 
    RETURN (SELECT @TheKey*2); 
END
GO

CREATE TABLE #tbl(MyKey INT,MyValue INT);
INSERT INTO #tbl(MyKey) VALUES(1),(1),(1),(2),(2),(3),(3),(3); 

SELECT * FROM #tbl;

DECLARE @tbl2 TABLE(MyKey INT,TheFooValue INT);
WITH DistinctKeys AS
(
    SELECT DISTINCT MyKey FROM #tbl
)
INSERT INTO @tbl2
SELECT MyKey,dbo.Foo(MyKey) TheFooValue
FROM DistinctKeys;

UPDATE #tbl SET MyValue=TheFooValue
FROM #tbl
INNER JOIN @tbl2 AS tbl2 ON #tbl.MyKey=tbl2.MyKey;

SELECT * FROM @tbl2;
SELECT * FROM #tbl;
GO

DROP TABLE #tbl;
DROP FUNCTION dbo.Foo;