我昨天正在跟进我的问题Entity Framework 6 get complext return value from a stored procedure。我的存储过程现在在实体框架下运行。但是,它在3分钟后超时,连接超时。
我在SQL Server Management Studio中使用该行运行存储过程(省略了客户信息):
EXEC spGetDupWOs @ProjectName=N'...', @City=N'...', @State=N'LA', @ProposalNum=N'201703080740-001', @County=N'...', @Owner=N'...', @QuoteRecipients=N'...', @ProjectID=-1
它在不到一秒的时间内执行。当实体框架执行它时,它需要永远。
使用SQL Server Profiler,我确定实体框架正在将此行发送到SQL服务器:
exec sp_executesql N'EXEC spGetDupWOs',N'@ProjectName nvarchar(19),@City nvarchar(6),@State nvarchar(2),@ProjectNum nvarchar(12),@County nvarchar(10),@Owner nvarchar(23),@QuoteRecipients nvarchar(23),@ProjectID bigint',@ProjectName=N'...',@City=N'Holden',@State=N'LA',@ProposalNum=N'201703080740-001',@County=N'Livingston',@Owner=N'...',@BID_RECIP=N'...',@ProjectID=-1
当我在SSMS中运行它时,它需要永远运行。
阅读类似的问题看起来问题是参数嗅探和执行计划的变化。
这是我在我的应用程序中执行存储过程的调用:
List<DuplicateProposals> duplicateCheckResults =
db.Database.SqlQuery<DuplicateProposals>("spGetDupWOs",
spl.ToArray())
.ToList();
在线阅读了一堆文章后,我更加困惑。如何更改我的电话以解决此问题?
答案 0 :(得分:0)
确定的问题是SQL Server中的参数嗅探。有多种方法可以解决这个问题,但最适合您的方案取决于您的实际用例,利用率等。
以下是一些选项。
每次执行时重新编译存储过程。这可能会变得非常繁重的CPU利用率,并且通常是过度的。除非你有充分的理由,否则我不推荐这个选项。实施:使用 在您的查询结尾处 WITH RECOMPILE 或 OPTION(RECOMPILE)提示。
优化提示。这可以是参数嗅探的变通方法,但可能会导致所有查询的subpar执行计划。通常,不是最佳方法。实施:使用选项(未知优化)
将参数复制到局部变量。在旧版本的SQL Server中更常见。实现:声明局部变量,然后将输入参数中的值复制到本地变量。 DECLARE @ local_var1 char(1)= @ InputParam1;
在查询级别关闭参数嗅探。此方法使用 QUERYTRACEON 提示。对于这种情况,这可能是最佳方法。我建议将此选项作为主要策略进行探索。要实现:在查询末尾添加 OPTION(QUERYTRACEON 4136)。
示例:
SELECT * FROM dbo.MyTable T
WHERE T.Col1 = @Param1 and T.Col2 = @Param2
OPTION(QUERYTRACEON 4136)
答案 1 :(得分:0)
我最终必须将整个调用转换为我传递给SqlQuery函数的单个字符串。
string sql = string.Format("exec spGetDupWOs @ProjectName=N'{0}',@City=N'{1}',@State=N'{2}',@ProjectNumber=N'{3}',@County=N'{4}',@Owner=N'{5}',@QuoteRecipients=N'{6}',@ProjectID={7}",
project.ProjectName,
project.City,
project.State,
project.ProjectNumber,
project.County,
project.Owner,
quoteRecipientsList,
"null");
是的,我必须在字符串中包含N前缀才能使其正常工作,我不知道为什么会这样做但是有效。
感谢所有人的帮助。没有你的帮助,我无法解决这个问题。