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

标签 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 
        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

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

最佳答案

我与 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;

关于sql-server - 单返回值的表值函数与标量值函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33993832/

相关文章:

sql-server - 如何根据条件生成Row_number()?

c# - 如何使用 Entity Framework Core 配置其他用户定义的数据类型?

sql-server - SQL Server 中 ALTER COLUMN 语句的幕后操作

sql-server - XML 服务器 XML 性能优化

sql - 根据列中的数字重复行

sql - 在 SQL Server 中以编程方式重命名表及其所有引用?

SQL Server - 如何从从上到下的数字列表中查询最大数字集

sql-server - 在 SQL Server 表中批量插入任何压缩格式

sql-server - SQL Server 中基于 empid wise 的连续行之间的分钟差异

sql - 4 列复合索引是否有益于 3 列查询?