我们正在使用正在执行从.NET到SQL Server的sp_executesql存储过程的调用的ORM。
当从.NET调用存储过程时,我们会收到超时异常。
查看Profiler,我可以看到查询确实需要很长时间才能执行。
查询基本上是:
exec sp_executesql N'SELECT DISTINCT
FROM [OurDatabase].[dbo].[Contract] [LPLA_1] ) [LPA_L1]
LEFT JOIN [OurDatabase].[dbo].[Customer] [LPA_L2] ON [LPA_L2].[Customer_ID]=[LPA_L1].[CustomerId] AND [LPA_L2].[Data]=[LPA_L1].[Data])
WHERE ( ( ( ( ( [LPA_L1].[DealerId] = @DealerId1))
AND ( [LPA_L2].[Last_Name] = @LastName2))))',N'@DealerId1 varchar(18),@LastName2 varchar(25)',@DealerId1='1234',@LastName2='SMITH'
对我来说令人困惑的部分是这样的:如果我将超时的查询复制并粘贴到SQL Management Studio并以交互方式执行它,它就可以正常执行。
有没有人知道为什么同一个查询在通过.NET代码执行时会花费更长的时间? (我能够重现这一点 - 从代码中执行的查询一直超时,并且以交互方式执行的查询始终正常工作。)
感谢任何帮助。谢谢!
答案 0 :(得分:4)
我见过几次的一件事是,如果索引字段上的查询参数的nvarchar和varchar类型不匹配。如果在数据库中使用varchar并且未在.Net中显式设置参数类型,则会发生这种情况,默认情况下将假定为nvarchar。
在这种情况下,Sql Server选择更正确的选项而不是更好的选项。而不是仅仅将您的参数转换为varchar,这将是一个可能会丢失信息的缩小转换,数据库将被强制将表中该列的每个值转换为nvarchar(保证成功而不会丢失信息) 。这不仅速度慢,而且Sql Server将无法再使用索引。不用说,查询将花费更长的时间来运行。
答案 1 :(得分:1)
我遇到同样的问题,从.net执行的过程需要花费太多时间(而且不会返回很多行)。我发送一个字符串给sql:“execute stored_procedure @ parameter1 = value1”然后我复制它并在sql management studio上运行但是一切都运行正常。这种情况的好处是,在我的查询中,我只是从参数值添加或删除LETTER导致它。我很困惑。
有关信息,我正在使用全文索引和临时表进行分页,但正如我所说,SAME QUERY(我确定)在sql management studio中运行完美。
答案 2 :(得分:1)
刚刚遇到同样的问题。
重建指数解决了这个问题。
问题可能在于varchar列上nvarchar vs index的参数类型......?
答案 3 :(得分:1)
我认为这是因为sp_executelsql是为了重新使用编译的查询计划,所以当同一个查询再次点击它时它不会重新嗅探参数,所以它最终会使用一个可能非常慢的计划(会告诉为什么一个较慢的查询计划)与当前参数values.it似乎是sp_executesql使用不同的方法来选择索引,显然它是一个破碎的方法与纯文本查询相比。
不同之处在于sp_executesql下的'Company(a table)'的表更新是通过一系列嵌套循环提供的,而文本查询是通过一串哈希匹配来提供的。视图的构造在两个版本之间看起来是相同的(我期望)。不幸的是,其余部分非常复杂,它们似乎在中间做了截然不同的事情;甚至拉动“实际”执行计划也没有给出查询的各个子组件的实际执行时间。实际上,我看不出sp_executesql以不同的方式选择任何内容的任何原因,但它可靠地构建了一个明显更慢的计划。
参数嗅探是一个解决方案,所以你应该重命名参数名称,或者甚至可以在where子句中交换列名,导致sp_executesql重新创建查询计划而不是使用旧的慢计划,当然这不是解决方案,但它不会缓慢缓慢计划这么久。
问候。
答案 4 :(得分:1)
这是我发现的。我有一个非常复杂的存储过程,总是计算信息,并将数据放在一个8列17行矩阵中,因为它每个月都被Crystal Reports调用/运行。 prod数据库是96 GB疯狂的快速服务器!最近它被缩小为32 GB的虚拟机。按比例缩小 - 它确实使应用程序在许多方面运行得更慢 - 直到添加了一些索引。
然后,本月的时间开始运行这个17行矩阵月度报告......正如您可以想象的那样,它超时了!
proc调用非常简单 - 3个参数。开始日期,结束日期和要过滤的区域 - null等于ALL。这两个日期作为一个字符从Crystal Reports传入,这些存储的PROC参数随后在整个疯狂的存储过程中被使用。
17行中的每一行 - 在计算/转入结果之前,基本上使用WITH语句和疯狂连接来查找数据行...这在本文中并不重要。
所以这里简化了......
CREATE PROCEDURE [dbo].[prcMonthlyStats]
@bDate datetime
,@eDate datetime
,@districtStr varchar(120)
AS
BEGIN
SET NOCOUNT ON;
...
--the @bDate and @eDate params were DIRECTLY used throughout the 2000 lines of SQL,
--to filter data inside and out of WITH statements and various other selects!
--
--TIMES OUT!
...
CREATE PROCEDURE [dbo].[prcMonthlyStats]
@bDateStr datetime
,@eDateStr datetime
,@districtStr varchar(120)
AS
BEGIN
SET NOCOUNT ON;
--FIX! Declare 2 date time variables and simply assign the 2 date time parameters to them.
DECLARE @bDate datetime
DECLARE @eDate datetime
DECLARE @district varchar(120)
--SET THE VARIABLES FROM THE PARAMETERS PASSED IN!
SET @bDate = @bDateStr
SET @eDate = @eDateStr
SET @district = @districtStr
.....
--PRESTO! The optimizer could once again use indexes as it should.
故事的寓意是 - 优化器能够通过使用DECLARED日期时间来完成它。
答案 5 :(得分:0)
dealerId或Lastname nvarchar(与varchar参数的输入方式不同)?
这可能导致整个索引的转换。如果您发现这种情况,请发表评论,我会更详细地解释。