问题 从Nhibernate执行的查询速度很慢,但是从ADO.NET开始很快


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

我已经看到类似于这个问题的类似问题,所以我进一步考虑了我的测试。

我使用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 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


8731
2017-10-13 11:46


起源

你在NHib代码中使用期货还是多品种? - Firo
究竟是什么查询? - Thilak Nathen
尝试使用nhprof,也许NH之后会发出其他查询,可能是N + 1问题。 - Chris Chilvers
嗨,只有一个查询。我已经使用过NHProf - psousa
很可能是参数嗅探。看到 “申请速度慢,SSMS速度快?” - Martin Smith


答案:


我有ADO.NET和NHibernate使用不同的查询计划,我更喜欢参数嗅探对NH版本的影响。为什么?因为我之前使用较小的日期间隔进行了查询,并且存储的查询计划已针对它进行了优化。

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

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

DBCC FREEPROCCACHE -- clears the query-plan cache

让我的查询再次快速。

我找到了两种方法来解决这个问题:

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

我尝试了两种选择,两种方法都有效,但选择了第二种方法。这是一点点 哈克 但我的情况非常好,因为数据是按日期统一分配的。


8
2017-10-21 17:27



我想指出“DBCC FREEPROCCACHE”清除整个缓存。这可能比你在一个有很多事情发生的系统(实际环境)中讨价还价。 - mcfea
这个答案 有一个如何使用拦截器添加的示例 OPTION OPTIMIZE FOR @p UNKNOWN 到查询结束。 - Groo
而不是调整查询,优化索引也可以解决这个问题。在我看来,调整指数应该是首选方式。参数嗅探主要是在查询索引不足(或缺少索引)时导致问题。但有时候很难为所有查询提供声音索引。 - Frédéric


我有与OP完全相同的问题。我试着@psousa建议注入“选项(重新编译)”,这确实提高了我的表现。但最后我发现简单地更新SQL Server的统计数据对我来说是个窍门。

update statistics tablename;

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


5
2018-02-23 22:41



+1表示有效答案。 - mcfea
这让我有了巨大的变化!谢谢! (更新统计数据) - alansiqueira27
这对我有用,并节省了我的一天。 - Marcos Brigante
@SkipHarris太棒了。这对我产生了巨大的改善 _sessionFactory.GetCurrentSession().CreateSQLQuery("update statistics [tablename];").ExecuteUpdate(); - onefootswill


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


2
2017-10-13 12:06



这是一个很好的提示,但不幸的是没有。参数是:@ 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“ - psousa
此外,在我的第二次测试中,应用程序很快,但直接使用ADO.NET而不是NH。 - psousa


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


0
2017-10-13 14:53



实际上没有,因为我比较的时间来自Sql Server Profiler(列“持续时间”),在数据甚至是水合之前。 - psousa