C# 使用SqlCommand参数时调用SQL函数的速度要慢得多

C# 使用SqlCommand参数时调用SQL函数的速度要慢得多,c#,sql,sql-server,performance,user-defined-functions,C#,Sql,Sql Server,Performance,User Defined Functions,我正在从C ASP.Net应用程序调用SQL函数UDF。我调用的函数需要一个uniqueidentifier类型的参数 如果我调用并在SqlCommand的CommandText中传递null,结果将在大约3秒钟后返回 SqlCommand Command = new SqlCommand(); Command.Connection = (SqlConnection)(DbDataModifier.CreateConnection()); Command.CommandText = "selec

我正在从C ASP.Net应用程序调用SQL函数UDF。我调用的函数需要一个uniqueidentifier类型的参数

如果我调用并在SqlCommand的CommandText中传递null,结果将在大约3秒钟后返回

SqlCommand Command = new SqlCommand();
Command.Connection = (SqlConnection)(DbDataModifier.CreateConnection());
Command.CommandText = "select * from GetLocalFirmLoginsSummary(null) order by Date asc"
Command.CommandType = CommandType.Text;

Command.Connection.Open();

SqlDataReader Reader = Command.ExecuteReader(); // takes 3 seconds
但是,如果我进行调用并将DBNull.Value作为SqlParameter传递,则返回结果需要60秒以上

SqlCommand Command = new SqlCommand();
Command.Connection = (SqlConnection)(DbDataModifier.CreateConnection());
Command.CommandText = "select * from GetLocalFirmLoginsSummary(@CustomerGroupID) order by Date asc"
Command.CommandType = CommandType.Text;

SqlParameter Param = new SqlParameter();
Param.ParameterName = "@CustomerGroupID";
Param.SqlDbType = SqlDbType.UniqueIdentifier;
Param.Direction = ParameterDirection.Input;
Param.IsNullable = true;
Param.Value = DBNull.Value;
Command.Parameters.Add(Param);

Command.Connection.Open();

SqlDataReader Reader = Command.ExecuteReader(); // takes over 60 seconds
如果在SQLManagementStudio中运行相同的查询,即使将null作为参数传递,也需要大约3秒钟的时间

declare @CustomerGroupID uniqueidentifier
set @CustomerGroupID = null

select * from GetLocalFirmLoginsSummary(@CustomerGroupID)
我调用的函数定义为:

将ANSI_空值设置为ON 去 在上设置带引号的\u标识符 去 ALTER函数[dbo]。[GetLocalFirmLoginsSummary] @CustomerGroupID唯一标识符 返回表 像 回来 选择CustomerGroupID、CustomerGroupName、USR、DATEADDMONTH、DATEDIFFMONTH、0、createdDate、0作为日期、COUNT*作为数量 来自dbo。GetLocalFirmLogins@CustomerGroupID作为登录名 按USR分组,CustomerGroupID,CustomerGroupName,DATEADDMONTH,DATEDIFFMONTH,0,createdDate,0

那么,当我使用SqlCommand的SqlParameter从C调用SQL函数时,是什么原因导致它花费了这么长的时间呢

我正在使用SQLServer2000


我已经搜索了所有地方,我能想到的每一个方面,但没有找到任何其他人有相同的问题。

吉姆,你能发布dbo.GetLocalFirmLogins的来源吗

正如马丁所说,这可能是参数嗅探。如果是,代码中的查询提示@CustomerGroupID的搜索可能是手术修复此问题的最佳方法

在dbo.GetLocalFirmLogins中将选项循环联接添加到查询中可能会在这里得到修复

我想我也可以解释为什么SSMS没有看到问题,而C没有看到问题。查询的这一部分:

(CustomerGroupID = @CustomerGroupID) OR (@CustomerGroupID IS NULL) 
根据您来自的连接的ANSI NULL设置,可能有两种不同的计划。ANSI NULL,其效果在此处说明:

通过检索此查询的结果,可以查看连接的ANSI设置:


SSM可能具有不同的NULL设置,您可以对其进行C代码编码,并导致对查询进行不同的计算。

Management Studio和.NET代码之间的性能差异通常与ANSI_NULL等设置有关

这可能是SQL Server 2000中的一个错误-请参阅,这似乎意味着未考虑在创建函数之前将ANSI_null设置为ON


我没有SQL Server 2000来测试这一点,但也许您可以尝试编写函数脚本。

这可能是由于SQL Server中的参数嗅探问题造成的

您可以在以下链接中找到更多详细信息:


我希望这会对您有所帮助。

当您说SQL时,您不是在说独立于数据库,而是在讨论Microsoft数据库产品,对吗?很可能是参数嗅探。您是否测试了它是否特定于null?什么是正常值?正如Martin所说,我怀疑这可能是参数嗅探,尝试获取参数变量,然后将其分配给局部变量,并在查询中使用局部变量,这可能有助于提高性能。在名为GetLocalFirmLogins的UDF中,由GetLocalFirmLoginsSummary调用,它在@CustomerGroupID上的过滤器为空。我现在已经将GetLocalFirmLogins添加到我的原始post.BTW的底部,我希望有一个可以在C代码中实现的解决方案,正如我希望的那样,我可以让其他SQL经验较少的人来调整UDF以满足他们的需要。我还发现,实际上我使用的是SQL Server 2000,而不是2008:我对参数嗅探做了一些阅读,除非我弄错了方向,这个问题不应该也适用于在SQL Management Studio中执行的查询吗?如果我在短信息中从查询窗口调用我的UDF,那么它既好又快。只有在从我的C代码中调用它们时,速度才慢。@JimRarbs-否。为了使应用程序使用的缓存计划能够被重用。SSMS有不同的默认set_选项,因此除非您使用不同于默认设置的选项,否则它不会重复使用应用程序使用的相同计划。有关详细信息,请参阅。通常不是设置本身。只是不同的设置意味着计划不会在会话之间共享,因此,不用为不具有代表性的参数使用已编译的缓存计划,您可以得到一个新的已编译计划,该计划执行良好。如果OP保持所有设置不变并清除计划缓存,问题可能会暂时消失,因为它可能在下次重新编译计划时再次出现。OK,我已使用与SSMS中相同的选项设置了C连接,包括ANSI_NULLS设置为ON。现在,当我用一个uniqueidentifier填充的参数调用UDF时,缓存计划显示它作为一个nvarchar36传递,但是当我用一个DBNull.Value作为参数调用它时,它似乎作为一个nvarchar4000传递,我猜这是导致性能问题的原因?为什么不总是这样
当我在UDF的定义中指定作为唯一标识符传递时,我可以确认nvarchar4000是问题所在。如果我在@CustomerGroupID和CustomerGroupID列引用周围放置一个CASTx作为NVARCHAR36,那么速度会显著提高。那么,如何强制Null参数值不作为NVARCHAR4000传递给SQL?@JimRarbs,您可以尝试设置参数Param.Size=。。。虽然我不知道为什么这对于UniqueIdentifier是必要的。@JimRarbs更改查询的文本将意味着同样不能使用错误的计划。没有特别的原因说明为什么一个会比另一个性能更好,尽管查看您的代码,我不确定为什么它使用nvarchar作为参数数据类型。看起来很奇怪。
(CustomerGroupID = @CustomerGroupID) OR (@CustomerGroupID IS NULL)