【问题标题】:Query executed from Nhibernate is slow, but from ADO.NET is fast从 Nhibernate 执行的查询很慢,但从 ADO.NET 执行的查询很快
【发布时间】:2011-12-06 21:44:20
【问题描述】:

我的 MVC 应用程序中有一个查询需要大约 20 秒才能完成(使用 NHibernate 3.1)。当我在 Management Studio 上手动执行查询时,需要 0 秒。

我在 SO 上看到过类似的问题,关于与此类似的问题,所以我将测试更进一步。

我使用 Sql Server Profiler 拦截了查询,并在我的应用程序中使用 ADO.NET 执行了查询。

我从 Profiler 得到的查询类似于:“exec sp_executesql N'select....”

我的 ADO.NET 代码:

SqlConnection conn = (SqlConnection) NHibernateManager.Current.Connection;

var query = @"<query from profiler...>";
var cmd = new SqlCommand(query, conn);

SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return RedirectToAction("Index");

这个查询也很快,不费时间去执行。

另外,我在 Profiler 上看到了一些非常奇怪的东西。该查询在从 NH 执行时具有以下统计信息:

读取:281702 写:0

来自 ADO.NET 的那个:

读取:333 写:0

有人知道吗?我可以提供任何信息来帮助诊断问题吗?

我认为这可能与某些连接设置有关,但 ADO.NET 版本使用的是来自 NHibernate 的相同连接。

提前致谢

更新:

我正在使用 NHibernate LINQ。该查询非常庞大,但它是一个分页查询,只获取了 10 条记录。

传递给“exec sp_executesql”的参数是:

@p0 整数,@p1 日期时间,@p2 日期时间,@p3 位,@p4 整数,@p5 整数

@p0=10,@p1='2009-12-01 00:00:00',@p2='2009-12-31 23:59:59',@p3=0,@p4=1, @p5=0

【问题讨论】:

  • 您在 NHib 代码中使用期货还是多标准?
  • 尝试使用 nhprof,也许 NH 之后会发出其他查询,可能是 N+1 问题。
  • 您好,只有一个查询。我已经用过NHProf
  • @Firo:不,不在这个查询中。
  • 很可能是参数嗅探。见"Slow in the Application, Fast in SSMS?"

标签: sql-server performance nhibernate ado.net


【解决方案1】:

我在 ADO.NET 和 NHibernate 中使用了不同的查询计划,并且我在 NH 版本上受到参数嗅探的影响。为什么?因为我之前做了一个小日期间隔的查询,并且存储的查询计划已针对它进行了优化。

之后,当查询的日期间隔较大时,使用了存储的计划,并且需要很长时间才能得到结果。

我确认这实际上是问题,因为一个简单的:

DBCC FREEPROCCACHE -- clears the query-plan cache

再次加快了我的查询速度。

我找到了两种解决方法:

  • 使用 NH 拦截器向查询注入“选项(重新编译)”
  • 在我的 NH Linq 表达式中添加一个虚拟谓词,例如:query = query.Where(true) 当预期的结果集很小时(日期间隔明智)。这样,将创建两种不同的查询计划,一种用于大型数据集,另一种用于小型数据集。

我尝试了这两个选项,并且都有效,但选择了第二种方法。这有点hacky,但在我的情况下效果很好,因为数据是按日期均匀分布的。

【讨论】:

  • 我想指出“DBCC FREEPROCCACHE”会清除整个缓存。这可能比你在一个有很多事情的系统中讨价还价(原文如此现场环境)。
  • This answer 有一个如何使用拦截器将OPTION OPTIMIZE FOR @p UNKNOWN 添加到查询末尾的示例。
  • 优化索引也可以解决这个问题,而不是调整查询。在我看来,调整索引应该是首选方式。参数嗅探主要在查询索引不足(或缺少索引)时引起问题。但有时很难为所有查询建立健全的索引。
【解决方案2】:

我遇到了与 OP 完全相同的问题。我尝试了@psousa 的注入“选项(重新编译)”的建议,这确实提高了我的性能。但最后我发现,简单地更新 SQL Server 上的统计信息对我有用。

update statistics tablename;

我最终退出了我的代码以注入“选项(重新编译)”。我知道这可能不是每个人的答案,但想分享,因为这是我的问题的原因。

【讨论】:

  • @SkipHarris 这么好。这给我带来了巨大的进步_sessionFactory.GetCurrentSession().CreateSQLQuery("update statistics [tablename];").ExecuteUpdate();
【解决方案3】:

查看提供给 sp_executesql 存储过程的参数。如果参数作为 nvarchar (N'value') 提供并且它们引用的列是 varchar,则 SQL Server 将使用非常低效的查询计划。这是我遇到的所有表现出这些症状的性能问题的根本原因(应用程序慢,SSMS 快)。

【讨论】:

  • 这是一个不错的提示,但不幸的是没有。参数为:@p0 int,@p1 datetime,@p2 datetime,@p3 bit,@p4 int,@p5 int',@p0=10,@p1='2009-12-01 00:00:00', @p2='2009-12-31 23:59:59',@p3=0,@p4=1,@p5=0"
  • 另外,在我的第二次测试中,应用程序很快,但直接使用 ADO.NET 而不是 NH。
【解决方案4】:

您没有指定查询或其结果集的大小,但是使用 nHibernate 获取大量实体时存在问题。
基本上,“水合”物体的时间就是这么长的时间。
您可以尝试打开反射优化器,或使用 IStatelessSession。
看看我收到的一些建议here

【讨论】:

  • 实际上没有,因为我要比较的时间来自 Sql Server Profiler(列“持续时间”),在数据还没有水合之前。
猜你喜欢
  • 2013-08-14
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 2022-11-18
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
  • 2021-07-23
相关资源
最近更新 更多