C# 后续执行中的值与原始值相差太大,计划将不是最优的
要纠正这种情况,可以在查询中指定C# 后续执行中的值与原始值相差太大,计划将不是最优的,c#,sql-server,performance,C#,Sql Server,Performance,要纠正这种情况,可以在查询中指定选项(重新编译)。将查询添加到存储过程不会帮助您解决此特定问题,除非 通过重新编译创建过程 其他人已经提到了这一点(“参数嗅探”),但我认为对这一概念的简单解释不会有什么坏处。我遇到了一个与此问题症状的标题完全匹配的问题 在我的例子中,问题是结果集被应用程序的.NET代码打开,而它在每个返回的记录中循环,并对数据库执行另外三个查询!超过数千行,这误导了原始查询,使其看起来像是根据SQL Server的计时信息完成得很慢 因此,修复方法是重构进行调用的.NET代码,
选项(重新编译)
。将查询添加到存储过程不会帮助您解决此特定问题,除非
通过重新编译创建过程
其他人已经提到了这一点(“参数嗅探”),但我认为对这一概念的简单解释不会有什么坏处。我遇到了一个与此问题症状的标题完全匹配的问题
在我的例子中,问题是结果集被应用程序的.NET代码打开,而它在每个返回的记录中循环,并对数据库执行另外三个查询!超过数千行,这误导了原始查询,使其看起来像是根据SQL Server的计时信息完成得很慢
因此,修复方法是重构进行调用的.NET代码,使其在处理每一行时不会打开结果集。在测试环境中也存在同样的问题,尽管实时系统(在同一SQL server上)运行正常。添加选项(重新编译)和选项(优化(@p1未知))没有帮助 我使用SQL Profiler捕获.net客户端发送的确切查询,发现该查询用
exec sp_executesql N'select…
包装,并且参数已声明为nvarchars-正在比较的列是简单的varchars
将捕获的查询文本放入SSMS后,确认其运行速度与从.net客户端运行时一样慢
我发现将参数类型更改为AnsiText可以解决问题:
p=cm.CreateParameter()
p、 ParameterName=“@公司”
p、 价值=公司
p、 DbType=DbType.AnsiString
cm.参数。添加(p)
我永远无法解释为什么测试环境和实时环境在性能上有如此显著的差异。我意识到OP没有提到存储过程的使用,但在使用存储过程时,有一种替代解决方案可以解决参数嗅探问题,它不太优雅,但在
选项(重新编译)时对我有效
似乎什么都不做
只需将您的参数复制到过程中声明的变量,然后使用它们即可
例如:
ALTER PROCEDURE [ExampleProcedure]
@StartDate DATETIME,
@EndDate DATETIME
AS
BEGIN
--reassign to local variables to avoid parameter sniffing issues
DECLARE @MyStartDate datetime,
@MyEndDate datetime
SELECT
@MyStartDate = @StartDate,
@MyEndDate = @EndDate
--Rest of procedure goes here but refer to @MyStartDate and @MyEndDate
END
在我的例子中,问题是我的实体框架正在生成使用
exec sp\u executesql
的查询
当参数在类型上不完全匹配时,执行计划不会使用索引,因为它决定将转换放入查询本身。
正如您可以想象的那样,这会导致更慢的性能
在我的例子中,列被定义为CHR(3),实体框架在查询中传递N'str',这导致从nchar到char的转换。因此,对于如下所示的查询:
ctx.Events.Where(e=>e.Status==“Snt”)
它正在生成一个SQL查询,如下所示:
来自[ExtEvents]作为[extt1]。。。
其中(N“Snt”=[Extent1].[Status])…
在我的例子中,最简单的解决方案是更改列类型,或者,您也可以首先努力使代码通过正确的类型。希望您的具体问题现在已经解决,因为这是一篇旧文章 以下
SET
选项可能会影响计划结果(末尾的完整列表)
以下两项声明来自
将ARITHABORT设置为OFF会对查询优化产生负面影响,从而导致性能问题
SQL Server Management Studio的默认arithaport设置为启用。将ARITHABORT设置为OFF的客户端应用程序可能会收到不同的查询计划,这使得对性能差的查询进行故障排除变得困难。也就是说,同一查询在ManagementStudio中执行得很快,但在应用程序中执行得很慢
另一个需要理解的有趣主题是参数嗅探
,如中所述
还有一种可能性是在使用Unicode输入参数时(内部)将VARCHAR列转换为NVARCHAR,如中所述
针对未知优化
在SQL Server 2008和以上中,考虑未知的优化。未知:指定查询优化器在查询优化期间使用统计数据而不是初始值来确定局部变量的值
选项(重新编译)
如果重新编译是唯一的解决方案,请使用“选项(重新编译)”而不是“使用重新编译”。它有助于参数嵌入优化。阅读
设置选项
以下SET
选项可能会影响计划重用,具体取决于
我今天遇到了这个问题,这解决了我的问题: 我把我的SP的开始放在这个:设置ARITHABORT
这帮你忙 我刚刚遇到了这个问题。针对在SSMS中返回次秒响应的视图运行的选择。但是运行sp_executesql需要5到20秒。为什么?因为当我通过sp_executesql运行时查看查询计划时,它没有使用正确的索引。它还进行索引扫描,而不是搜索。对我来说,解决方案只是创建一个简单的sp,用传递的参数执行查询。当通过sp_executesql运行时,它使用了正确的索引,并且没有进行扫描。如果您想进一步改进它,请确保在有sp时使用command.CommandType=CommandType.StoredProcedure,然后它不使用sp_executesql,它只使用EXEC,但这只减少了ms的结果 这段代码在一个有数百万条记录的数据库上运行了不到一秒
public DataTable FindSeriesFiles(string StudyUID)
{
DataTable dt = new DataTable();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = new SqlCommand("VNA.CFIND_SERIES", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("@StudyUID", StudyUID);
using (SqlDataReader reader = command.ExecuteReader())
{
dt.Load(reader);
}
return dt;
}
}
}
using (SqlConnection conn = new SqlConnection("<CONNECTION_STRING>")) {
conn.Open();
using (SqlCommand comm = new SqlCommand("SET ARITHABORT ON", conn)) {
comm.ExecuteNonQuery();
}
// Do your own stuff here but you must use the same connection object
// The SET command applies to the connection. Any other connections will not
// be affected, nor will any new connections opened. If you want this applied
// to every connection, you must do it every time one is opened.
}
object value = cmd.ExecuteScalar();
if (value == null)
return 0;
else
return (double)value;
cmd.Parameters.Add("@TrustAccountID1", SqlDbType.Int).Value = trustAccountId;
cmd.Parameters.Add("@UserID1", SqlDbType.Int).Value = userId;
cmd.Parameters.Add("@TrustAccountID2", SqlDbType.Int).Value = trustAccountId;
cmd.Parameters.Add("@UserID2", SqlDbType.Int).Value = userId;
cmd.Parameters.Add("@TrustAccountID", SqlDbType.Int).Value = trustAccountId;
cmd.Parameters.Add("@UserID", SqlDbType.Int).Value = userId;
select TrustAccountValue from
(
SELECT MAX (tal.trustaccountlogid), tal.TrustAccountValue
FROM TrustAccountLog AS tal
INNER JOIN TrustAccount ta ON ta.TrustAccountID = tal.TrustAccountID
INNER JOIN Users usr ON usr.UserID = ta.UserID
WHERE usr.UserID = 70402 AND
ta.TrustAccountID = 117249 AND
tal.TrustAccountLogDate < '3/1/2010 12:00:00 AM'
group by tal.TrustAccountValue
) q
set language us_english
go
select @@language --us_english
select convert(datetime, '3/1/2010 12:00:00 AM')
go
set language british
go
select @@language --british
select convert(datetime, '3/1/2010 12:00:00 AM')
select convert(datetime, '20100301 00:00:00') --midnight 00, noon 12
tal.TrustAccountLogDate < @TrustAccountLogDate2
ALTER PROCEDURE [ExampleProcedure]
@StartDate DATETIME,
@EndDate DATETIME
AS
BEGIN
--reassign to local variables to avoid parameter sniffing issues
DECLARE @MyStartDate datetime,
@MyEndDate datetime
SELECT
@MyStartDate = @StartDate,
@MyEndDate = @EndDate
--Rest of procedure goes here but refer to @MyStartDate and @MyEndDate
END
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
SET ARITHABORT ON
GO
public DataTable FindSeriesFiles(string StudyUID)
{
DataTable dt = new DataTable();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = new SqlCommand("VNA.CFIND_SERIES", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("@StudyUID", StudyUID);
using (SqlDataReader reader = command.ExecuteReader())
{
dt.Load(reader);
}
return dt;
}
}
}
CREATE PROCEDURE [VNA].[CFIND_SERIES]
@StudyUID NVARCHAR(MAX)
AS BEGIN
SET NOCOUNT ON
SELECT *
FROM CFIND_SERIES_VIEW WITH (NOLOCK)
WHERE [StudyInstanceUID] = @StudyUID
ORDER BY SeriesNumber
END
public DataTable FindSeriesFiles(string StudyUID)
{
DataTable dt = new DataTable();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText =" SELECT * FROM CFIND_SERIES_VIEW WITH (NOLOCK) WHERE StudyUID=@StudyUID ORDER BY SeriesNumber";
command.Parameters.AddWithValue("@StudyUID", StudyUID);
using (SqlDataReader reader = command.ExecuteReader())
{
dt.Load(reader);
}
return dt;
}
}
}