【问题标题】:Avoid calling T-SQL function multiple times避免多次调用 T-SQL 函数
【发布时间】:2020-10-08 16:39:25
【问题描述】:

我有一个内联函数,导致在 T-SQL 脚本执行期间我需要多次。该函数的结果非常大。我想弄清楚如何只调用一次函数。

这是我的功能:

CREATE OR ALTER FUNCTION getRecords (@earliestDate Datetime, @token1 varchar(64), @token2 varchar(64))
RETURNS TABLE
AS
RETURN
(
    SELECT  CONVERT(DATE, LogDate) AS LogDate, UserType, UserStatus
        FROM LogTable WITH (NOLOCK)
        WHERE UserStatus = 'Active'
            AND LogDate >= @earliestDate
            AND (token = @token1 OR token = @token2)
        GROUP BY LogDate, UserType, UserStatus
);
GO

我需要稍后在脚本的不同位置使用结果。例如:

DECLARE @token1 varchar(64) = '1111'
DECLARE @token2 varchar(64) = '9999'
DECLARE @earliestDate Datetime='2020-09-01';

SELECT Product, UserType, 

    (SELECT COUNT(DISTINCT UserStatus) 
        FROM getRecords (@earliestDate, @token1, @token2) AS GR
        
        INNER JOIN mySecondTable AS ST
        ON GR.UserType = ST.UserType 
    ) AS MyCount

FROM  ProductTypes INNER JOIN getRecords (@earliestDate, @token1, @token2) AS GR2
ON ProductTypes.UserType = GR2.UserType;
WHERE ProductTypes.avail = 1;

这是一个很长的脚本。我需要在不同的步骤中使用结果。我尝试创建一个临时表,但过程太慢了。

上述查询有效,但我想让它更有效率。

一如既往,感谢您的任何建议。

【问题讨论】:

  • 停止喷溅nolock everywhere。除非您了解后果、有使用它的正当理由并接受可能引发的错误,否则请勿使用该提示。
  • 由于每次调用函数时使用的参数都完全相同,我建议您使用临时表而不是函数。
  • 谢谢@SMor,我不知道 NOLOCK。我会调查的。
  • 嗨@JMabee,我想这就是我最终要做的。我以前试过,但花了很长时间。我会调查的。

标签: sql sql-server tsql inline-functions


【解决方案1】:

在 SQL 引擎中调用函数可能非常慢。我建议创建一个视图,然后加入该视图——这应该会快得多。如果我有时间,我会给你一个例子

"如果我使用视图,是否可以多次使用视图结果,还是每次使用时都会重新创建视图结果?"

每次都会“重新创建”结果,但查询会被编译,这意味着您可以获得很多提升的性能。根据平台的不同,如果数据不脏,系统甚至可以缓存对数据的重用查询。

另请注意,大多数系统都能够创建“物化视图”,然后会执行一次查询并将其存储为表,直到您要求重新计算为止。这在 SQL Server、Oracle 和 DB2 上的工作方式不同,但您可以获得相同的功能。

对于某些系统可以向视图添加参数(称为令人震惊的参数化视图),但我不建议这样做 - 根据您的数据模型,可能有更好的方法来执行此功能(在您的情况下,我会这样做例如,在我从视图中选择之后进行分组。

还记得

  AND (token = @token1 OR token = @token2)

与

相同
    AND token IN (@token1, @token2)

但有些平台可能不支持以这种方式使用参数。在这种情况下,您可能可以使用这样的连接

WITH filter(t) AS 
(
   VALUES  (@token1),
           (@token2)
)
SELECT x
FROM  y
JOIN filter ON filter.t = y.token

【讨论】:

  • 感谢霍根的评论。我有一个后续问题:如果我使用视图,我可以多次使用视图结果还是每次使用时都会重新创建视图结果?现在,我可以将变量传递给函数,我不认为我可以为视图做同样的事情,可以吗?
  • 内联表函数通常与视图一样快,因为它们的扩展方式与视图相同。
  • @DaleK -- 非常正确。我假设函数的有用性在于它可以重复使用,这有时对于内联函数来说很难做到——但对于 CTE 或视图来说并不那么难
猜你喜欢
  • 2017-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多