Sql server 2008 SQL Server性能问题:为什么简单SQL语句和UD标量值函数看起来很昂贵

Sql server 2008 SQL Server性能问题:为什么简单SQL语句和UD标量值函数看起来很昂贵,sql-server-2008,database-performance,Sql Server 2008,Database Performance,我们的SQL 2008 r2数据库遇到了一些严重的性能问题。当我们在SQL Server Management Studio中运行“活动监视器”和返回活动对象的SP时,会显示以下三个事务非常昂贵: 查询1: SET @DateMonth = '0' + @DateMonth SET @DateMonth = CAST(datepart(mm, @TheDate) AS VARCHAR(2)) CREATE FUNCTION [dbo].[DateToNGDate] (@TheDate dat

我们的SQL 2008 r2数据库遇到了一些严重的性能问题。当我们在SQL Server Management Studio中运行“活动监视器”和返回活动对象的SP时,会显示以下三个事务非常昂贵:

查询1:

SET @DateMonth = '0' + @DateMonth
SET @DateMonth = CAST(datepart(mm, @TheDate) AS VARCHAR(2))
CREATE FUNCTION [dbo].[DateToNGDate] (@TheDate datetime)
RETURNS VARCHAR(10)
AS
BEGIN
            DECLARE @DateYear VARCHAR(4)
            DECLARE @DateMonth VARCHAR(2)
            DECLARE @DateDay VARCHAR(2)

            SET @DateYear = CAST(datepart(yyyy, @TheDate) AS VARCHAR(4))

            SET @DateMonth = CAST(datepart(mm, @TheDate) AS VARCHAR(2))
            IF (LEN (@DateMonth) = 1) SET @DateMonth = '0' + @DateMonth

            SET @DateDay = CAST(datepart(dd, @TheDate) AS VARCHAR(2))
            IF (LEN (@DateDay) = 1) SET @DateDay = '0' + @DateDay

            RETURN @DateYear+@DateMonth+@DateDay
END
查询2:

SET @DateMonth = '0' + @DateMonth
SET @DateMonth = CAST(datepart(mm, @TheDate) AS VARCHAR(2))
CREATE FUNCTION [dbo].[DateToNGDate] (@TheDate datetime)
RETURNS VARCHAR(10)
AS
BEGIN
            DECLARE @DateYear VARCHAR(4)
            DECLARE @DateMonth VARCHAR(2)
            DECLARE @DateDay VARCHAR(2)

            SET @DateYear = CAST(datepart(yyyy, @TheDate) AS VARCHAR(4))

            SET @DateMonth = CAST(datepart(mm, @TheDate) AS VARCHAR(2))
            IF (LEN (@DateMonth) = 1) SET @DateMonth = '0' + @DateMonth

            SET @DateDay = CAST(datepart(dd, @TheDate) AS VARCHAR(2))
            IF (LEN (@DateDay) = 1) SET @DateDay = '0' + @DateDay

            RETURN @DateYear+@DateMonth+@DateDay
END
功能:

SET @DateMonth = '0' + @DateMonth
SET @DateMonth = CAST(datepart(mm, @TheDate) AS VARCHAR(2))
CREATE FUNCTION [dbo].[DateToNGDate] (@TheDate datetime)
RETURNS VARCHAR(10)
AS
BEGIN
            DECLARE @DateYear VARCHAR(4)
            DECLARE @DateMonth VARCHAR(2)
            DECLARE @DateDay VARCHAR(2)

            SET @DateYear = CAST(datepart(yyyy, @TheDate) AS VARCHAR(4))

            SET @DateMonth = CAST(datepart(mm, @TheDate) AS VARCHAR(2))
            IF (LEN (@DateMonth) = 1) SET @DateMonth = '0' + @DateMonth

            SET @DateDay = CAST(datepart(dd, @TheDate) AS VARCHAR(2))
            IF (LEN (@DateDay) = 1) SET @DateDay = '0' + @DateDay

            RETURN @DateYear+@DateMonth+@DateDay
END
最后一个是这样返回的,但我很确定它不是在创建函数(它已经存在),而是在运行它。它也是表现得最像性能杀手的一个(它在我们的代码中都有使用)


我确信这些并不是问题的真正原因,但为什么它们看起来像这样?

在SQL Server中,标量值函数是一个已知的性能问题。一个选项是如下定义函数:

CREATE FUNCTION [dbo].[DateToNGDateX] (@TheDate datetime)
RETURNS table as return 
(
    select
        cast(
              CAST(datepart(yyyy, @TheDate) AS VARCHAR(4)) -- DateYear 
            + right('0' + CAST(datepart(mm, @TheDate) AS VARCHAR(2)),2) -- DateMonth 
            + right('0' + CAST(datepart(dd, @TheDate) AS VARCHAR(2)),2) -- DateDay 
        as varchar(30)) as Value
)
select Value from [dbo].[DateToNGDateX] ('20140110');
并参照如下:

CREATE FUNCTION [dbo].[DateToNGDateX] (@TheDate datetime)
RETURNS table as return 
(
    select
        cast(
              CAST(datepart(yyyy, @TheDate) AS VARCHAR(4)) -- DateYear 
            + right('0' + CAST(datepart(mm, @TheDate) AS VARCHAR(2)),2) -- DateMonth 
            + right('0' + CAST(datepart(dd, @TheDate) AS VARCHAR(2)),2) -- DateDay 
        as varchar(30)) as Value
)
select Value from [dbo].[DateToNGDateX] ('20140110');
但是,对于所需的特定功能,也要进行测试:

select convert(char(8), cast('20140110' as date), 112);

它将返回格式为yyyymmdd的日期。

如果select语句返回大量行,标量UDF将非常慢,因为它们将对返回的每一行执行一次。也许您可以根据此链接重写为内联函数

我喜欢Pieter Geerkens的答案,我希望它解决了您的问题。无论在何处使用,标量函数都将返回每个匹配行的结果。所以它类似于游标。表值函数将接受一个集合并返回一个集合

要验证两个进程之间的I\O更改,management studio可能没有帮助,但在您自己的计算机上,您可以放置一个小的跟踪,以查看性能的大小


干杯

这怎么会突然成为我们的大问题?多年来,这从来不是一个问题(6+),但毫无疑问,它正在扼杀我们。此外,这不是我们在内部编写的函数,我们支持一个名为NextGen的EHR产品,这是他们的一个库存函数。@jreed121:我无法解释为什么EHR的员工中会有不知道这个问题的无监督初级程序员;你得跟他们谈谈。至于为什么它突然成为一个问题,我建议发布一个查询计划。无论如何,实现此功能的正确方法是使用我上面描述的两种方法之一,并测试哪种方法在您的环境中工作得最好。