我接管了一些C#代码.
代码正在使用一些SQL使用参数的数据库.
所有字符串参数都是键入DbType.AnsiString而不是DbType.String.
你为什么要用DbType.AnsiString而不是DbType.String?
我有一个存储过程接受一个日期输入,如果没有传入值,则该日期输入稍后设置为当前日期:
CREATE PROCEDURE MyProc
@MyDate DATETIME = NULL
AS
IF @MyDate IS NULL SET @MyDate = CURRENT_TIMESTAMP
-- Do Something using @MyDate
Run Code Online (Sandbox Code Playgroud)
我遇到问题,如果@MyDate在NULL第一次编译存储过程时传入if ,则对于所有输入值(NULL或其他),性能总是很糟糕,如果在编译存储过程时传入日期/当前日期性能适用于所有输入值(NULL或其他).
令人困惑的是,即使实际 使用@MyDate的值NULL(而不是CURRENT_TIMESTAMP由IF语句设置),生成的糟糕执行计划也很糟糕
我发现禁用参数嗅探(通过欺骗参数)修复了我的问题:
CREATE PROCEDURE MyProc
@MyDate DATETIME = NULL
AS
DECLARE @MyDate_Copy DATETIME
SET @MyDate_Copy = @MyDate
IF @MyDate_Copy IS NULL SET @MyDate_Copy = CURRENT_TIMESTAMP
-- Do Something using @MyDate_Copy
Run Code Online (Sandbox Code Playgroud)
我知道这与参数嗅探有关,但我看到的所有"参数嗅探变坏"的例子都涉及使用传递的非代表性参数编译存储过程,但是在这里我看到了执行计划是可怕的SQL Server可能认为执行该语句其中参数可能需要在该点所有可能的值- NULL,CURRENT_TIMESTAMP或以其他方式.
有没有人知道为什么会这样?
我的查询相当复杂,但我已经简化了它来解决这个问题,现在它是一个简单的JOIN,我正在SQL Server 2014数据库上运行.查询是:
SELECT * FROM SportsCars as sc INNER JOIN Cars AS c ON c.CarID = sc.CarID WHERE c.Type = 1
Run Code Online (Sandbox Code Playgroud)
当我从SMSS运行此查询并在SQL事件探查器中观察它时,执行大约需要350毫秒.当我使用Entity Framework或ADO.NET在我的应用程序中运行相同的查询时(我已尝试过两者).执行需要4500ms.
ADO.NET代码:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var cmdA = new SqlCommand("SET ARITHABORT ON", connection);
cmdA.ExecuteNonQuery();
var query = "SELECT * FROM SportsCars as sc INNER JOIN Cars AS c ON c.CarID = sc.CarID WHERE c.Type = 1";
var cmd = new SqlCommand(query, connection);
cmd.ExecuteNonQuery()
}
Run Code Online (Sandbox Code Playgroud)
在SQL Server Management Studio中执行时,我有一个查询(大约1600行存储为存储过程),执行大约需要3秒(在通过添加正确的索引进行优化之后).
我在C#中为此编写了一个包装器,并为自己提供了使用URI来执行此查询的能力.但是,这需要超过30秒的时间来执行,因此,当我将此查询作为循环的一部分运行时,由于过多的待处理请求,浏览器会停止.我写了这样的包装器:
try
{
string ConString = Constants.connString;
using (con = new SqlConnection(ConString))
{
cmd = new SqlCommand(sql, con);
con.Open();
dr = cmd.ExecuteReader();
while (dr.Read())
{
...
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的连接字符串是这样的:
Data Source={0};Initial Catalog={1};Integrated Security=True;MultipleActiveResultSets=true
Run Code Online (Sandbox Code Playgroud)
我知道查询本身很好,因为我在SSMS中多次运行它并且工作正常(平均5秒以下).而且,我很乐意提供更多的调试信息,除了我不知道提供什么.
要解决这些问题,我将从哪里开始?
编辑:
我运行了SQL Profiler并收集了一些统计信息.这就是我所观察到的.非常奇怪,它是正在执行的确切查询.让我知道在这一点上我还能做些什么.
