Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 用户定义函数最佳实践_Sql_Sql Server_Tsql_Sql Server 2008 - Fatal编程技术网

Sql 用户定义函数最佳实践

Sql 用户定义函数最佳实践,sql,sql-server,tsql,sql-server-2008,Sql,Sql Server,Tsql,Sql Server 2008,我正在考虑在一些查询中使用一些用户定义的函数调用,而不是使用一堆内联case语句。内联语句可能会执行得更好,但函数使其更易于查看和维护 我只是想了解一下UDF的典型最佳实践是什么?我意识到在标准(Where子句)中使用它们会对性能产生一些重大影响 特别是在case块中可以有很多when语句,甚至可以有嵌套case语句的情况下 谢谢 不要仅仅为了美观而使用函数。这可以通过使用一致的代码格式来处理 在您描述的情况下,您创建了一个外部依赖项——该函数必须存在,并且对用户可见,查询才能运行。直到SQL

我正在考虑在一些查询中使用一些用户定义的函数调用,而不是使用一堆内联case语句。内联语句可能会执行得更好,但函数使其更易于查看和维护

我只是想了解一下UDF的典型最佳实践是什么?我意识到在标准(Where子句)中使用它们会对性能产生一些重大影响

特别是在case块中可以有很多when语句,甚至可以有嵌套case语句的情况下

谢谢


不要仅仅为了美观而使用函数。这可以通过使用一致的代码格式来处理

在您描述的情况下,您创建了一个外部依赖项——该函数必须存在,并且对用户可见,查询才能运行。直到SQL Server支持与Oracle包相同的内容(程序集不是本机SQL)


还有一种风险是,人们可能会误认为SQL函数的执行方式与过程式/面向对象编程中的方法/函数类似,它们没有这样做,因此查询在使用函数时比不使用函数时执行得更差。

我倾向于避免使用大多数函数,因为虽然它们比内联case语句更漂亮,但它们也会使查询计划的准确性降低。如果您在函数中隐藏了大量复杂性,那么复杂性也会从查询计划中隐藏,因此,如果您有问题并且以后需要优化查询,您通常会修复一些显示为高成本但实际上与UDF相比成本微不足道的问题。

我的固定答案:

普遍存在一种误解,即自定义项对性能有负面影响。总而言之,这根本不是事实。事实上,内联表值UDF实际上是宏——优化器能够很好地重写涉及它们的查询并优化它们。然而,标量UDF通常非常慢。我将提供一个简短的例子

先决条件

以下是创建和填充表的脚本:

CREATE TABLE States(Code CHAR(2), [Name] VARCHAR(40), CONSTRAINT PK_States PRIMARY KEY(Code))

GO

INSERT States(Code, [Name]) VALUES('IL', 'Illinois')

INSERT States(Code, [Name]) VALUES('WI', 'Wisconsin')

INSERT States(Code, [Name]) VALUES('IA', 'Iowa')

INSERT States(Code, [Name]) VALUES('IN', 'Indiana')

INSERT States(Code, [Name]) VALUES('MI', 'Michigan')

GO

CREATE TABLE Observations(ID INT NOT NULL, StateCode CHAR(2), CONSTRAINT PK_Observations PRIMARY KEY(ID))

GO

SET NOCOUNT ON

DECLARE @i INT

SET @i=0

WHILE @i<100000 BEGIN

  SET @i = @i + 1

  INSERT Observations(ID, StateCode)

  SELECT @i, CASE WHEN @i % 5 = 0 THEN 'IL'

    WHEN @i % 5 = 1 THEN 'IA'

    WHEN @i % 5 = 2 THEN 'WI'

    WHEN @i % 5 = 3 THEN 'IA'

    WHEN @i % 5 = 4 THEN 'MI'

    END

END

GO
并将其与涉及内联表值UDF的查询进行比较:

CREATE FUNCTION dbo.GetStateName_Inline(@StateCode CHAR(2))

RETURNS TABLE

AS

RETURN(SELECT [Name] FROM dbo.States WHERE Code = @StateCode);

GO

SELECT ID, (SELECT [name] FROM dbo.GetStateName_Inline(StateCode)) AS StateName

  INTO dbo.ObservationsWithStateNames_Inline

  FROM dbo.Observations
它的执行计划和执行成本都是相同的——优化器将其重写为外部连接。不要低估优化器的威力

涉及标量UDF的查询要慢得多。

下面是一个标量UDF:

CREATE FUNCTION dbo.GetStateName(@StateCode CHAR(2))

RETURNS VARCHAR(40)

AS

BEGIN

  DECLARE @ret VARCHAR(40)

  SET @ret = (SELECT [Name] FROM dbo.States WHERE Code = @StateCode)

  RETURN @ret

END

GO
显然,使用此UDF的查询提供了相同的结果,但它有不同的执行计划,而且速度非常慢:

/*

SQL Server parse and compile time:

   CPU time = 0 ms, elapsed time = 3 ms.

Table 'Worktable'. Scan count 1, logical reads 202930, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Observations'. Scan count 1, logical reads 188, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.



SQL Server Execution Times:

   CPU time = 11890 ms,  elapsed time = 38585 ms.

*/
如您所见,优化器可以重写和优化涉及内联表值UDF的查询。另一方面,涉及标量UDF的查询不会被优化器重写——最后一个查询的执行每行包含一个函数调用,这非常慢。
抄袭自

感谢OMG我感谢您的反馈。“最近从Oracle切换”出于安全原因,最佳做法是不使用函数。这仅适用于标量UDF,而对于内联UDF则完全错误。您不应在标量函数中查询表。时期SQL Server根本没有优化它们。它们甚至被排除在查询计划之外。您实际上是在SQL中编写一个N+1查询。N+1查询是魔鬼,永远不会执行。
/*

SQL Server parse and compile time:

   CPU time = 0 ms, elapsed time = 3 ms.

Table 'Worktable'. Scan count 1, logical reads 202930, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Observations'. Scan count 1, logical reads 188, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.



SQL Server Execution Times:

   CPU time = 11890 ms,  elapsed time = 38585 ms.

*/