首页 > 解决方案 > 如何防止 .NET 变成 EXEC 的 SELECT 语句中的参数嗅探?

问题描述

我有一个 SQL SELECT 语句,它在 SQL Server Management Studio 中运行得非常快(5 秒),但在我的 ASP.NET 代码中运行得非常慢。

我读过这可能与参数嗅探有关。当我从 SSMS 运行 SELECT 语句时,我使用的是 SELECT。但是当我观看 SQL Profiler 时,我的 SELECT 语句作为存储过程执行,其模式为: exec sp_executesql N'SELECT foo FROM bar WHERE userid = @userid',N'@userid int',@userid=2

此 ASP.NET 代码在四分钟后超时(连接字符串设置):

SqlCommand objCommand = new SqlCommand("SELECT foo FROM bar WHERE userid = @userid", objCS);
SqlDataReader reader;
objCommand = new SqlCommand("", objCS);
objCommand.CommandType = CommandType.Text;
objCommand.Parameters.Add("@userid", SqlDbType.Int).Value = 1;
SqlDataReader reader = objCommand.ExecuteReader();

//超时 objCommand.ExecuteReader();

此代码在 5 秒内在 SQL Server Management Studio 中执行:

DECLARE @userid AS Int = 2
SELECT foo FROM bar WHERE userid = @userid

在 5 秒内返回 60000+ 行。

如何使 ASP.NET 代码作为 SELECT 语句而不是存储过程执行,同时保留参数化存储过程的安全值?

编辑:我认为这可能与使用 SQL 语句运行代码的不同用户与在 SSMS 中运行 SQL 语句的用户有关。从代码运行的用户具有不同的服务器权限,包括对表的有限访问。SQL 语句包含一个视图,并且用户没有对该视图中所有表的基础 SELECT 访问权限。这是否也意味着他们无法获得统计数据?

标签: c#sqlasp.netsql-server

解决方案


如果确实是参数嗅探(您必须查看实际计划才能确定),并且您肯定拥有正确的索引,您可以更新查询以使用索引提示,但 IMO 这不是最佳方式. 如果您可以将查询放入存储过程中,则您可以将存储过程标记为 WITH RECOMPILE,因此它不会重用第一个计划。IMO,这比强制索引提示更好。


推荐阅读