为什么与 SqlCommand 一起使用时某些 sql 查询会慢很多?

发布于 2024-07-17 12:32:15 字数 1916 浏览 2 评论 0原文

我有一个存储过程,从 Sql Server Management Studio 执行(2 秒)比使用 System.Data.SqlClient.SqlCommand 运行(2 分钟后超时)要快得多。

这可能是什么原因?


细节: 在 Sql Server Management Studio 中,这将在 2 秒内运行(在生产数据库上):

EXEC sp_Stat
    @DepartmentID = NULL

在 .NET/C# 中,2 分钟后会超时(在生产数据库上):

string selectCommand = @"
EXEC sp_Stat
    @DepartmentID = NULL";
string connectionString = "server=***;database=***;user id=***;pwd=***";
using (SqlConnection connection = new SqlConnection(connectionString))
{
    using (SqlCommand command = new SqlCommand(selectCommand, connection))
    {
        connection.Open();
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
            }
        }
    }
}

我还尝试了 selectCommand = "sp_Stat"CommandType = StoredProcedureSqlParameter,但结果相同。

如果没有 EXEC ,结果也是一样的。

在几乎数据为空的开发数据库上,这两种情况都在不到 1 秒的时间内完成。 因此,这与数据库中有大量数据有关,但它似乎只发生在 .NET 中......


Marc Gravell 所写的关于不同 SET 值的内容在所呈现的情况下产生了差异。

SQL Server Profiler 显示 Sql Server Management Studio 运行以下 SET,而 .NET Sql Client Data Provider 则不会:


SET ROWCOUNT 0 
SET TEXTSIZE 2147483647 
SET NOCOUNT OFF 
SET CONCAT_NULL_YIELDS_NULL ON 
SET ARITHABORT ON 
SET LOCK_TIMEOUT -1 
SET QUERY_GOVERNOR_COST_LIMIT 0 
SET DEADLOCK_PRIORITY NORMAL 
SET TRANSACTION ISOLATION LEVEL READ COMMITTED 
SET ANSI_NULLS ON 
SET ANSI_NULL_DFLT_ON ON 
SET ANSI_PADDING ON 
SET ANSI_WARNINGS ON 
SET CURSOR_CLOSE_ON_COMMIT OFF 
SET IMPLICIT_TRANSACTIONS OFF 
SET QUOTED_IDENTIFIER ON
SET NOEXEC, PARSEONLY, FMTONLY OFF

当我包含这些时,相同的查询在 SSMS 和 .NET 中花费相同的时间。网。 而负责的SET是......

SET ARITHABORT ON

我学到了什么? 也许使用探查器而不是猜测......

(解决方案起初似乎与参数嗅探有关。但我混淆了一些东西......)

I have a stored procedure that executes much faster from Sql Server Management Studio (2 seconds) than when run with System.Data.SqlClient.SqlCommand (times out after 2 minutes).

What could be the reason for this?


Details:
In Sql Server Management Studio this runs in 2 seconds (on production database):

EXEC sp_Stat
    @DepartmentID = NULL

In .NET/C# the following times out after 2 minutes (on production database):

string selectCommand = @"
EXEC sp_Stat
    @DepartmentID = NULL";
string connectionString = "server=***;database=***;user id=***;pwd=***";
using (SqlConnection connection = new SqlConnection(connectionString))
{
    using (SqlCommand command = new SqlCommand(selectCommand, connection))
    {
        connection.Open();
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
            }
        }
    }
}

I also tried with selectCommand = "sp_Stat", CommandType = StoredProcedure, and an SqlParameter, but it's the same result.

And without EXEC it's the same result as well.

On an almost data-empty development database both cases finishes in less than 1 second. So it's related to that there's a lot of data in the database, but it seems to only happen from .NET...


What Marc Gravell wrote about different SET values makes the difference in the presented case.

SQL Server Profiler showed that Sql Server Management Studio runs the following SET's that .NET Sql Client Data Provider does not:


SET ROWCOUNT 0 
SET TEXTSIZE 2147483647 
SET NOCOUNT OFF 
SET CONCAT_NULL_YIELDS_NULL ON 
SET ARITHABORT ON 
SET LOCK_TIMEOUT -1 
SET QUERY_GOVERNOR_COST_LIMIT 0 
SET DEADLOCK_PRIORITY NORMAL 
SET TRANSACTION ISOLATION LEVEL READ COMMITTED 
SET ANSI_NULLS ON 
SET ANSI_NULL_DFLT_ON ON 
SET ANSI_PADDING ON 
SET ANSI_WARNINGS ON 
SET CURSOR_CLOSE_ON_COMMIT OFF 
SET IMPLICIT_TRANSACTIONS OFF 
SET QUOTED_IDENTIFIER ON
SET NOEXEC, PARSEONLY, FMTONLY OFF

When I included these, the same query took the same amount of time in SSMS and .NET.
And the responsible SET is ...

SET ARITHABORT ON

What have I learnt? Maybe to use a profiler instead of guessing...

(The solution at first seemed to be related to parameter sniffing. But I had mixed some things up...)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

何处潇湘 2024-07-24 12:32:15

另一件重要的事情是SET选项 已启用。 其中一些选项足以更改查询计划以更改配置文件。 如果您正在查看(例如)计算+持久(并且可能是索引)列,有些可能会产生巨大影响:如果 SET 选项不兼容,则可能会被迫重新计算值,而不是使用索引值 - 这可以将索引查找更改为表扫描+计算。

尝试使用探查器查看哪些 SET 选项正在“发挥作用”,并查看使用这些选项是否会改变情况。

另一个影响是连接字符串; 例如,如果启用 MARS,可以以微妙的方式改变行为。

最后,事务(隐式 (TransactionScope) 或显式)可能会产生巨大影响,具体取决于隔离级别。

Another thing that can be important is the SET options that are enabled. Some of these options change the query plan sufficiently to change the profile. Some can have a huge impact if you are looking at (for example) a calculated + persisted (and possibly indexed) column: if the SET options aren't compatible, it can be forced to re-calculate the values, rather than using the indexed value - which can change an index seek into a table scan + calculation.

Try using the profiler to see what SET options are "in play", and see if using those options changes things.

Another impact is the connection string; for example, if you enable MARS that can change the behaviour in subtle ways.

Finally, transactions (implicit (TransactionScope) or explicit) can have a huge impact, depending on the isolation level.

誰認得朕 2024-07-24 12:32:15

这几乎肯定是由于“不正确”的缓存查询计划造成的。 这个问题已经出现过很多次了。

您有最新的统计数据吗? 定期安排索引维护计划?

您可以通过将其添加到存储过程定义中来测试这是否肯定是由于缓存的查询计划造成的:

CREATE PROCEDURE usp_MyProcedure WITH RECOMPILE...

这将重新索引整个数据库(如果数据库非常大,请小心!):

exec sp_msforeachtable "dbcc dbreindex('?')"

SO posts:

Managment Studio 和 TableAdapter 之间存储过程的执行时间存在巨大差异.

SQL Server 中的参数嗅探(或欺骗)

针对 SQL Server 2005 的未知进行优化?

同一存储过程的不同执行计划

This is almost certainly due to an 'incorrect' cached query plan. This has come up on SO quite a few times.

Do you have up-to-date statistics? A regular scheduled index maintenance plan?

You can test if it is definitely due to the cached query plan by adding this to your stored procedure definition:

CREATE PROCEDURE usp_MyProcedure WITH RECOMPILE...

This will re-index an entire database (caution if database is very large!):

exec sp_msforeachtable "dbcc dbreindex('?')"

SO posts:

Big difference in execution time of stored proc between Managment Studio and TableAdapter.

Parameter Sniffing (or Spoofing) in SQL Server

optimize for unknown for SQL Server 2005?

Different Execution Plan for the same Stored Procedure

纸伞微斜 2024-07-24 12:32:15

遇到了类似的问题,结果发现连接字符串中的 MultipleActiveResultSets=true (应该影响最小)导致通过远程连接提取 150 万条记录需要 25 分钟,而不是大约 2 分钟。

Had a similar issue and it turns out having MultipleActiveResultSets=true in the connection string (which is supposed to have minimal impact) was making pulling 1.5mil records over a remote connection take 25 minutes instead of around 2 minutes.

最佳男配角 2024-07-24 12:32:15

我们遇到了一个类似的问题,在 SSMS 中查询将在 2 秒内完成,而从 .NET 客户端调用时则需要 90 秒以上(我们编写了几个 VB/C# 应用程序/站点来测试它。)

我们怀疑查询计划会有所不同,并使用显式循环(“内循环连接”和“带索引”)提示重写查询。 这解决了问题。

We had a similiar issue, where a query would complete in 2 seconds in SSMS and take more than 90 seconds when called from a .NET client (we wrote several VB/C# apps/sites to test it.)

We suspected that the query plan would be different, and rewrote the query with explicit looping ("inner loop join" and "with index") hints. This solved the problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文