8

我们正在使用一个 ORM,它正在执行从 .NET 到 SQL Server 的 sp_executesql 存储过程的调用。

当从 .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 代码执行相同的查询需要更长的时间?(我能够重现这一点——从代码执行的查询始终超时,并且以交互方式执行的查询始终可以正常工作。)

任何帮助表示赞赏。谢谢!

4

6 回答 6

4

我见过几次的一件事是,如果索引字段上的查询参数的 nvarchar 和 varchar 类型不匹配。如果您在数据库中使用 varchar 并且未在 .Net 中显式设置参数的类型,则可能会发生这种情况,默认情况下将假定为 nvarchar。

在这种情况下,Sql Server 会选择更正确的选项,而不是性能更好的选项。而不是仅仅将您的参数转换为 varchar,这将是一个可能会丢失信息的缩小转换,数据库将被迫将表中该列的每个值转换为 nvarchar(保证成功而不会丢失信息) . 不仅速度很慢,而且 Sql Server 将无法再使用索引。不用说,查询将花费更长的时间来运行。

于 2009-10-02T13:46:51.463 回答
1

我有同样的麻烦,从 .net 执行的过程需要太多时间(并且不会返回很多行)。我向 sql 发送了一个字符串:“execute stored_procedure @parameter1 = value1”,然后我将其复制并在 sql management studio 上运行,但一切运行正常。这种情况的核心是,在我的查询中,我只是从参数值中添加或删除了一个 LETTER 来导致它。我很困惑。

对于信息,我正在使用全文索引和临时表进行分页,但就像我说的那样,SAME QUERY(我敢肯定)在 sql management studio 中完美运行。

于 2009-12-13T00:56:21.933 回答
1

我认为这是因为 sp_exectelsql 旨在重用已编译的查询计划,所以当同一个查询再次命中它时它不会重新嗅探参数,所以它最终会使用一个可能非常慢的计划(会告诉你为什么较慢的查询计划)使用当前参数值。似乎 sp_executesql 使用不同的方法来选择索引,与纯文本查询相比,它显然是一种损坏的方法。

不同的是 sp_executesql 下的“公司(表)”的表更新是通过嵌套循环链提供的,而文本查询是通过哈希匹配链提供的。两个版本之间的视图构造似乎相同(我希望如此)。不幸的是,其余部分非常复杂,而且它们似乎在中间做着完全不同的事情。即使拉出“实际”执行计划也不会给出查询的各个子组件的实际执行时间。真的,我看不出 sp_executesql 选择任何不同的任何理由,但它可靠地构建了一个明显慢得多的计划。

参数嗅探是一种解决方案,因此您应该重命名参数名称,或者您甚至可能在 where 子句中交换列名,这会导致 sp_executesql 重新创建查询计划而不是使用旧的慢速计划,当然这不是解决方案,但是它不会缓存一个较慢的计划这么久。

问候。

于 2012-06-19T11:41:17.950 回答
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 日期时间来完成它的事情。

于 2012-10-03T19:23:26.197 回答
1

只是有同样的问题。

重建索引解决了这个问题。

也许问题在于参数的类型是 nvarchar 与 varchar 列上的索引...?

于 2010-12-01T15:04:32.200 回答
0

是dealerId 还是Lastname nvarchar(与varchar 参数的类型不同)?

这可能会导致整个索引的转换。如果您发现是这种情况,请发表评论,我会更详细地解释。

于 2009-10-02T13:45:24.430 回答