Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.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 server 单返回值的表值函数与标量值函数_Sql Server_Sql Server 2012_Sql Server 2014 - Fatal编程技术网

Sql server 单返回值的表值函数与标量值函数

Sql server 单返回值的表值函数与标量值函数,sql-server,sql-server-2012,sql-server-2014,Sql Server,Sql Server 2012,Sql Server 2014,我从一个定标器函数返回单个值,如下所示: CREATE FUNCTION [dbo].[GetNoOfAssignedCases] ( @UserID INT, @FromD DATETIME, @ToD DATETIME ) RETURNS NVARCHAR(MAX) AS BEGIN DECLARE @CaseCount INT = 0 SELECT @CaseCount = COUNT(1) FROM Cases WHERE

我从一个定标器函数返回单个值,如下所示:

CREATE FUNCTION [dbo].[GetNoOfAssignedCases]
(
    @UserID INT,
    @FromD DATETIME,
    @ToD DATETIME
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
    DECLARE @CaseCount INT = 0
    SELECT @CaseCount = COUNT(1) FROM Cases
    WHERE 
        CaseAssignedToAssessor = @UserID AND 
        CAST(ActionDateTime AS DATE) >= @FromD AND
        CAST(ActionDateTime AS DATE) <= @ToD
    RETURN @CaseCount
END
SELECT [Name], [DBO].[GetNoOfAssignedCases](UserID, GETDATE()-30, GETDATE()) FROM Users

可以用表值函数替换它吗它会对性能产生影响吗?哪个更快?

表值函数将如下所示:

CREATE FUNCTION [dbo].[GETNOOFASSIGNEDCASES] (@UserID INT,
                                              @FromD  DATETIME,
                                              @ToD    DATETIME)
RETURNS @CaseCount TABLE (
  cnt INT NULL )
AS
  BEGIN
      INSERT INTO @CaseCount
                  (cnt)
      SELECT Count(1)
      FROM   Cases
      WHERE  CaseAssignedToAssessor = @UserID
             AND Cast(ActionDateTime AS DATE) >= @FromD
             AND Cast(ActionDateTime AS DATE) <= @ToD
  END 

表值函数如下所示:

CREATE FUNCTION [dbo].[GETNOOFASSIGNEDCASES] (@UserID INT,
                                              @FromD  DATETIME,
                                              @ToD    DATETIME)
RETURNS @CaseCount TABLE (
  cnt INT NULL )
AS
  BEGIN
      INSERT INTO @CaseCount
                  (cnt)
      SELECT Count(1)
      FROM   Cases
      WHERE  CaseAssignedToAssessor = @UserID
             AND Cast(ActionDateTime AS DATE) >= @FromD
             AND Cast(ActionDateTime AS DATE) <= @ToD
  END 

是的,你可以这样做(未经测试)

创建函数[dbo]。[GetNoOfAssignedCases]
(
@UserID INT,
@FromD DATETIME,
@ToD日期时间
)
返回表
作为
返回
选择计数(1)作为案例计数
从案例
哪里
casesassignedtoasessor=@UserID和
CAST(ActionDateTime作为日期)>=@FromD和

CAST(ActionDateTime作为日期)是的,您可以这样做(未经测试)

创建函数[dbo]。[GetNoOfAssignedCases]
(
@UserID INT,
@FromD DATETIME,
@ToD日期时间
)
返回表
作为
返回
选择计数(1)作为案例计数
从案例
哪里
casesassignedtoasessor=@UserID和
CAST(ActionDateTime作为日期)>=@FromD和
强制转换(ActionDateTime作为日期)
它会对性能产生影响吗

对。我们非常广泛地使用函数。在优化特定查询时,我发现SQL将标量值函数作为一个单独的实体进行优化,其中TVF“内联”到主查询中,然后作为一个整体进行优化。例外情况可能存在,但我们发现TVF普遍更快(只比自己内联函数稍微慢一点)

可以用表值函数替换它吗

对。如果您担心的是性能,则应使用以下格式:

CREATE FUNCTION [dbo].[GetNoOfAssignedCases]
(
    @UserID INT,
    @FromD DATETIME,
    @ToD DATETIME
)
RETURNS TABLE
AS RETURN
    SELECT COUNT(1) AS Count FROM Cases
    WHERE 
        CaseAssignedToAssessor = @UserID AND 
        CAST(ActionDateTime AS DATE) >= @FromD AND
        CAST(ActionDateTime AS DATE) <= @ToD;
您需要
RETURN选择
,才能进行“内联”。此外,您的工作是确保这些函数不会返回多个记录(除非您确实想要交叉应用
行为,而您几乎从未这样做)

它会对性能产生影响吗

对。我们非常广泛地使用函数。在优化特定查询时,我发现SQL将标量值函数作为一个单独的实体进行优化,其中TVF“内联”到主查询中,然后作为一个整体进行优化。例外情况可能存在,但我们发现TVF普遍更快(只比自己内联函数稍微慢一点)

可以用表值函数替换它吗

对。如果您担心的是性能,则应使用以下格式:

CREATE FUNCTION [dbo].[GetNoOfAssignedCases]
(
    @UserID INT,
    @FromD DATETIME,
    @ToD DATETIME
)
RETURNS TABLE
AS RETURN
    SELECT COUNT(1) AS Count FROM Cases
    WHERE 
        CaseAssignedToAssessor = @UserID AND 
        CAST(ActionDateTime AS DATE) >= @FromD AND
        CAST(ActionDateTime AS DATE) <= @ToD;

您需要
RETURN选择
,才能进行“内联”。此外,您的工作是确保这些函数不会返回多个记录(除非您确实想要交叉应用<代码>行为,而您几乎从来没有这样做过)。

我与Jonatha Dickinson的讨论(查看他的答案)让我做了一些快速测试:

结果表明,纯的、嵌入的标量子选择并没有那么糟糕。只查询一个值,它甚至是最快的。正如所料,标量函数是错误的。TVF返回的场越多,相对性能增益越好

唯一确定的答案是:标量函数是最差的,多行TVF在大多数情况下比内联的慢任何临时方法都会更快

但我可以为所有情况设置特殊情况(标量函数除外),其中一种方法最快

结论:(一如既往:-)这取决于

提示:最好是在一个包含许多表和列的大型数据库中进行此操作

CREATE FUNCTION dbo.CountColumnScalar(@TableSchema AS VARCHAR(100),@TableName AS VARCHAR(100))
RETURNS INT
AS
BEGIN
    RETURN(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName);
END
GO
CREATE FUNCTION dbo.CountConstraintScalar(@TableSchema AS VARCHAR(100),@TableName AS VARCHAR(100))
RETURNS INT
AS
BEGIN
    RETURN(SELECT COUNT(*) FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName);
END
GO

CREATE FUNCTION dbo.CountAllTVF(@TableSchema AS VARCHAR(100),@TableName AS VARCHAR(100))
RETURNS TABLE
RETURN SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS ColCounter
             ,(SELECT COUNT(*) FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS ConstraintCounter    ;
GO
CREATE FUNCTION dbo.CountAllTVF_multiline(@TableSchema AS VARCHAR(100),@TableName AS VARCHAR(100))
RETURNS @tbl TABLE (ColCounter INT,ConstraintCounter INT)
AS
BEGIN
INSERT INTO @tbl
SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS ColCounter
      ,(SELECT COUNT(*) FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS ConstraintCounter;
RETURN;
END
GO

DECLARE @time DATETIME=GETDATE();
SELECT TABLE_SCHEMA,TABLE_NAME
     ,(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS AS c WHERE c.TABLE_SCHEMA=t.TABLE_SCHEMA AND c.TABLE_NAME=t.TABLE_NAME ) AS ColCounter
     ,(SELECT COUNT(*) FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c WHERE c.TABLE_SCHEMA=t.TABLE_SCHEMA AND c.TABLE_NAME=t.TABLE_NAME ) AS ConstraintCounter
FROM INFORMATION_SCHEMA.TABLES AS t;
PRINT 'pure embedded scalar sub-select: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();


SELECT TABLE_SCHEMA,TABLE_NAME
     ,dbo.CountColumnScalar(t.TABLE_SCHEMA,t.TABLE_NAME ) AS ColCounter 
     ,dbo.CountConstraintScalar(t.TABLE_SCHEMA,t.TABLE_NAME ) AS ConstraintCount 
FROM INFORMATION_SCHEMA.TABLES AS t
PRINT 'scalar function: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();


SELECT t.TABLE_SCHEMA,t.TABLE_NAME
      ,colJoin.ColCount
      ,conJoin.ConstraintCount 
FROM INFORMATION_SCHEMA.TABLES AS t
INNER JOIN (SELECT COUNT(*) As ColCount,c.TABLE_SCHEMA,c.TABLE_NAME 
            FROM INFORMATION_SCHEMA.COLUMNS AS c 
            GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS colJoin ON  colJoin.TABLE_SCHEMA=t.TABLE_SCHEMA AND colJoin.TABLE_NAME=t.TABLE_NAME
INNER JOIN (SELECT COUNT(*) As ConstraintCount,c.TABLE_SCHEMA,c.TABLE_NAME 
            FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c 
            GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS conJoin ON  conJoin.TABLE_SCHEMA=t.TABLE_SCHEMA AND conJoin.TABLE_NAME=t.TABLE_NAME
PRINT 'JOINs on sub-selects: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();

SELECT t.TABLE_SCHEMA,t.TABLE_NAME
      ,ColCounter.*
FROM INFORMATION_SCHEMA.TABLES AS t
CROSS APPLY dbo.CountAllTVF(t.TABLE_SCHEMA,t.TABLE_NAME) AS ColCounter
PRINT 'TVF inline: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();


SELECT t.TABLE_SCHEMA,t.TABLE_NAME
      ,ColCounter.*
FROM INFORMATION_SCHEMA.TABLES AS t
CROSS APPLY dbo.CountAllTVF_multiline(t.TABLE_SCHEMA,t.TABLE_NAME) AS ColCounter
PRINT 'TVF multiline: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();
GO

DROP FUNCTION dbo.CountColumnScalar;
DROP FUNCTION dbo.CountAllTVF;
DROP FUNCTION dbo.CountAllTVF_multiline;
DROP FUNCTION dbo.CountConstraintScalar;

我与Jonatha Dickinson的讨论(看看他的答案)让我做了一些快速测试:

结果表明,纯的、嵌入的标量子选择并没有那么糟糕。只查询一个值,它甚至是最快的。正如所料,标量函数是错误的。TVF返回的场越多,相对性能增益越好

唯一确定的答案是:标量函数是最差的,多行TVF在大多数情况下比内联的慢任何临时方法都会更快

但我可以为所有情况设置特殊情况(标量函数除外),其中一种方法最快

结论:(一如既往:-)这取决于

提示:最好是在一个包含许多表和列的大型数据库中进行此操作

CREATE FUNCTION dbo.CountColumnScalar(@TableSchema AS VARCHAR(100),@TableName AS VARCHAR(100))
RETURNS INT
AS
BEGIN
    RETURN(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName);
END
GO
CREATE FUNCTION dbo.CountConstraintScalar(@TableSchema AS VARCHAR(100),@TableName AS VARCHAR(100))
RETURNS INT
AS
BEGIN
    RETURN(SELECT COUNT(*) FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName);
END
GO

CREATE FUNCTION dbo.CountAllTVF(@TableSchema AS VARCHAR(100),@TableName AS VARCHAR(100))
RETURNS TABLE
RETURN SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS ColCounter
             ,(SELECT COUNT(*) FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS ConstraintCounter    ;
GO
CREATE FUNCTION dbo.CountAllTVF_multiline(@TableSchema AS VARCHAR(100),@TableName AS VARCHAR(100))
RETURNS @tbl TABLE (ColCounter INT,ConstraintCounter INT)
AS
BEGIN
INSERT INTO @tbl
SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS ColCounter
      ,(SELECT COUNT(*) FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c WHERE c.TABLE_SCHEMA=@TableSchema AND c.TABLE_NAME=@TableName GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS ConstraintCounter;
RETURN;
END
GO

DECLARE @time DATETIME=GETDATE();
SELECT TABLE_SCHEMA,TABLE_NAME
     ,(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS AS c WHERE c.TABLE_SCHEMA=t.TABLE_SCHEMA AND c.TABLE_NAME=t.TABLE_NAME ) AS ColCounter
     ,(SELECT COUNT(*) FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c WHERE c.TABLE_SCHEMA=t.TABLE_SCHEMA AND c.TABLE_NAME=t.TABLE_NAME ) AS ConstraintCounter
FROM INFORMATION_SCHEMA.TABLES AS t;
PRINT 'pure embedded scalar sub-select: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();


SELECT TABLE_SCHEMA,TABLE_NAME
     ,dbo.CountColumnScalar(t.TABLE_SCHEMA,t.TABLE_NAME ) AS ColCounter 
     ,dbo.CountConstraintScalar(t.TABLE_SCHEMA,t.TABLE_NAME ) AS ConstraintCount 
FROM INFORMATION_SCHEMA.TABLES AS t
PRINT 'scalar function: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();


SELECT t.TABLE_SCHEMA,t.TABLE_NAME
      ,colJoin.ColCount
      ,conJoin.ConstraintCount 
FROM INFORMATION_SCHEMA.TABLES AS t
INNER JOIN (SELECT COUNT(*) As ColCount,c.TABLE_SCHEMA,c.TABLE_NAME 
            FROM INFORMATION_SCHEMA.COLUMNS AS c 
            GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS colJoin ON  colJoin.TABLE_SCHEMA=t.TABLE_SCHEMA AND colJoin.TABLE_NAME=t.TABLE_NAME
INNER JOIN (SELECT COUNT(*) As ConstraintCount,c.TABLE_SCHEMA,c.TABLE_NAME 
            FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS c 
            GROUP BY c.TABLE_SCHEMA,c.TABLE_NAME) AS conJoin ON  conJoin.TABLE_SCHEMA=t.TABLE_SCHEMA AND conJoin.TABLE_NAME=t.TABLE_NAME
PRINT 'JOINs on sub-selects: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();

SELECT t.TABLE_SCHEMA,t.TABLE_NAME
      ,ColCounter.*
FROM INFORMATION_SCHEMA.TABLES AS t
CROSS APPLY dbo.CountAllTVF(t.TABLE_SCHEMA,t.TABLE_NAME) AS ColCounter
PRINT 'TVF inline: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();


SELECT t.TABLE_SCHEMA,t.TABLE_NAME
      ,ColCounter.*
FROM INFORMATION_SCHEMA.TABLES AS t
CROSS APPLY dbo.CountAllTVF_multiline(t.TABLE_SCHEMA,t.TABLE_NAME) AS ColCounter
PRINT 'TVF multiline: ' + CAST(CAST(GETDATE()-@time AS TIME) AS VARCHAR(MAX)); SET @time=GETDATE();
GO

DROP FUNCTION dbo.CountColumnScalar;
DROP FUNCTION dbo.CountAllTVF;
DROP FUNCTION dbo.CountAllTVF_multiline;
DROP FUNCTION dbo.CountConstraintScalar;

在这种情况下,人们应该总是更喜欢即席(或内联)UDF!并注意没有案例的用户。更好地使用
OUTER APPLY
…在这种情况下,您应该始终更喜欢即席(或内联)UDF!并注意没有案例的用户。更好地使用
OUTER APPLY
…您刚刚编辑了关于性能的问题和询问:这取决于。。。如果您必须一次性为所有用户获得一个计数器,最快的可能是老式的
分组方式
。。。带有
APPLY
的内联UDF应该与带有子选择的
JOIN
完全相同。这肯定比多行的标量计算或多语句UDF快。有多少行(在
用户
案例
)?关于更多提示:询问性能,您应该阅读“可搜索表达式”。您的
CAST(ActionDateTime…
将不可搜索…@Shnugo将有100多个用户和20000多个案例。我正在使用其他3个类似的函数,根据一个选择的不同条件获取计数。因此,我不认为我可以使用group by。如果在
案例
(以及其他表格)中外键上有索引,那么一个简单的计数肯定会永远不要导致性能问题。正如我在回答中所说,内联自定义项与子选择上的联接大致相同,如果同时对多个用户进行联接,则比逐行联接好得多。嗨,我很好奇:你能解决你的问题吗?您选择了哪种方法?您刚刚编辑了您的问题并询问了有关性能的问题:这取决于。。。如果你必须得到一个co