ADO.NET与SSMS中的SQL Server性能比较

5
在开始之前,我已经阅读了几篇关于在ADO和SSMS中执行SQL语句/存储过程时遇到性能问题的帖子。 我花费了大部分时间尝试自己解决这个问题...重新建立索引,使用sp_recompile,向我的存储过程中添加Option(Recompile)。 什么都没有奏效,所以我转向社区寻求帮助。
我的一个Web应用程序执行的存储过程用于运行报告。 特别是,这个存储过程由大多数动态SQL组成,以允许返回不同的报告结果......在我的站点上具有一种动态报告功能。 不管怎样,某些报告可以运行(使用相同的过程),并且结果几乎立即返回。 然而,其他选项可能被使用,过程可能需要几分钟才能运行。 然而,在SSMS中手动使用相同选项运行该过程会立即返回结果。 这听起来像某种计划缓存问题,但是在重新编译过程并添加WITH(RECOMPILE)之后,它在ADO.NET中仍然运行得非常慢。
因此,我开始查看SQL配置文件,也许ADO正在使用的某个“SET”命令会导致问题。 但是,在使用完全相同的SET命令后,它仍然在SSMS中几乎立即返回。
我尝试使用DBCC freeproccache和DBCC freesystemcache清除任何存储的计划,但是这也没有帮助。
我尝试另一种方法,就是将在过程中生成的动态SQL直接运行在SqlCommand语句中。 这里没有参数,只有纯SQL。 在SSMS中再次运行时立即执行,但在ADO.NET中需要很长时间。
有没有一种方法(运行ADO.NET)可以查看生成的计划? 我可以在SSMS中做到这一点,但这对我没有帮助,因为它在SSMS中运行良好。
如果有帮助的话,这是原始的SQL语句...
SELECT sf.ID [FileID], sb.ID [BillID], sb.Client_BillID, sf.BobID [ClientID], c.Name [ClientName], c.Parent_ID [ParentID], pnt.Name [ParentName], Network_ID, Facility_Name, OON, sb.TaxID, Inpatient, sf.ProcessDate, sb.Reversed, sb.State, sb.Product, sb.FormType, n.Direct 
INTO #t1 FROM SubmitterFiles sf WITH(NOLOCK) 
INNER JOIN SubmitterBills sb WITH (NOLOCK) ON sf.ID = sb.FileID 
LEFT JOIN PPORecords r WITH (NOLOCK) ON sb.RecordID = r.ID 
LEFT JOIN PPONetworks n WITH (NOLOCK) ON r.Network_ID = n.ID 
LEFT JOIN PPOProviders p WITH (NOLOCK) ON r.Provider_ID = p.ID 
INNER JOIN Clients c WITH (NOLOCK) ON sf.BobID = c.ID 
LEFT JOIN Clients pnt WITH (NOLOCK) ON c.Parent_ID = pnt.ID 
WHERE sf.ProcessDate BETWEEN 'Dec  1 2012 12:00AM' and 'Dec 31 2012 12:00AM' 
AND ISNULL(sb.Status,'') NOT IN ('E','V') 
AND (c.Parent_ID IN (1989) or c.ID  IN (1989)) 
; 

SELECT TOP 100 0 as [placeholder],NULL AS BillID, NULL AS Client_BillID, NULL AS DOS
,NULL AS Network_ID
,NULL AS Client_ID
,NULL AS Client_Name
,NULL As ProcessDate
,NULL As ProcessMonth
,NULL AS SubClientID
,NULL AS SubClientName
,Product
,TaxID
, FacilityName
, LastName
, FirstName
,State
,County
,NULL As ProcCode
,NULL As FormType
,NULL As Inpatient, NULL AS Outpatient
,COUNT(DISTINCT sb.BillID) AS [Total_Bills]
,SUM(sl.Amount) AS  [Total_Charges]
,SUM(sl.StateSavings) AS [Total_StateSavings]
,SUM(sl.PPOSavings) AS [Total_PPOSavings]
,COUNT(DISTINCT TaxID) AS [Total_Unique_TaxIds]
,0,0,0,0,0
,COUNT(DISTINCT CASE WHEN sb.OON = 1 THEN sb.BillID ELSE NULL END) AS [Out_Bills]
,SUM(CASE WHEN sb.OON = 1 THEN sl.Amount ELSE 0 END) AS [Out_Charges]
,SUM(CASE WHEN sb.OON = 1 THEN sl.StateSavings ELSE 0 END) AS [Out_StateSavings]
,COUNT(DISTINCT CASE WHEN sb.OON = 1 THEN sb.TaxID ELSE NULL END) AS [Out_Unique_TaxIds]
,0,0,0,0,0
,0,0,0,0,0
 FROM SubmitterLines sl  WITH (NOLOCK, INDEX(IX_SubmitterLines_BillID))
 INNER JOIN #t1 sb WITH(NOLOCK) ON sl.BillID = sb.BillID
 INNER JOIN SubmitterBillProviders sbp WITH(NOLOCK) ON sb.BillID = sbp.ID
 INNER JOIN SubmitterBillZipCounty sbc WITH(NOLOCK) ON sb.BillID = sbc.ID
 WHERE 1 = 1
GROUP BY Product
,TaxID
,FacilityName, LastName, FirstName
,State
,County
ORDER BY [Out_Bills] DESC

2
请在标签“ADO.NET”中将标题更正为“ADO”。 - Hamlet Hakobyan
1
我强烈建议放弃存储过程中的动态SQL,否则执行计划将始终不如任务的最佳选择。就像SQL无法很好地计划执行标量函数一样,动态SQL总是会带来意外,系统将难以优化其执行。 - Darth Continent
1
Darth - 动态SQL有其适用的场景。我知道它不会是最优的,但它似乎不是当前问题的原因。提取SQL并执行仍然会复制该问题。 - Brosto
你尝试过添加查询提示 OPTION (OPTIMIZE FOR UNKNOWN) 吗? - YS.
@DarthContinent:这是不正确的。动态SQL潜在的性能问题与子优化执行计划无关,而是与必须生成执行计划有关。相比参数化SQL,动态SQL更有可能需要生成唯一的查询计划。这个小额外工作就是为什么动态SQL可能会更慢的原因。然而,有些常见情况(报告往往是其中之一)生成每次唯一的计划比重用一个对所有参数值都不高效的公共计划更有效率。 - RBarryYoung
显示剩余5条评论
2个回答

1
这是昨晚让我熬夜的问题之一,所以我又开始仔细检查了一遍。最后我终于想到,在SSMS中,我的默认行数设置为1000。但有点困扰的是,当我在SQL Profiler中运行跟踪时,这个设置并没有显示在其他SET中。将ROWCOUNT设置回0使我能够在SSMS中重现此问题,从而查看执行计划并修复导致查询运行缓慢的问题。
归根结底,这不是ADO的问题 - 而是我在SSMS中设置的限制返回常规行数的设置。由于我的查询的一部分构建了一个更大结果集的临时表,因此该临时表只被填充了1000行。

1
未来读者注意:根据http://msdn.microsoft.com/en-us/library/ms188774.aspx的相关说明,微软在未来的SQL Server版本中将对此进行一些更改:“在下一个SQL Server版本中,使用SET ROWCOUNT将不会影响DELETE、INSERT和UPDATE语句。在新的开发工作中避免使用SET ROWCOUNT与DELETE、INSERT和UPDATE语句,并计划修改当前使用它的应用程序。” - Kprof

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接