簡體   English   中英

NHibernate SQL查詢速度慢

[英]NHibernate SQL query slow

我正在使用LINQ to NH來獲取應用啟動時的大量數據。 我特意添加了ToList()來強制立即執行查詢:

Group group = GetGroup();
Log.Info("started");
var list = Session.Linq<Data>()
    .Where(p => p.Group.Id == group.Id)
    .OrderByDescending(p => p.Stamp.Counter) /* Stamp is composite mapping */
    .Select(p => new
    {
        Counter = p.Stamp.Counter,
        Status = p.Status,
    })
    .Take(4000)
    .ToList();
Log.Info("done");

檢查NHibernate.SQL記錄器的DEBUG日志會按預期提供以下SQL(當我開始監視時,同樣的查詢在SQL事件探查器中彈出):

SELECT top 4000 this_.Counter as y0_, this_.Status as y1_
FROM [Data] this_ 
LEFT OUTER JOIN [Group] group1_ ON this_.Group_id=group1_.Id
WHERE group1_.Id = @p0 
ORDER BY this_.Counter desc; @p0 = 1

問題是,從我的應用程序調用時,此查詢需要2分鍾才能完成,而在SSMS中執行則需要0.5秒! 實際上,當應用程序正在等待查詢完成時,我可以在SSMS中執行它並立即獲得結果。

你認為這種差異來自哪里?

由於沒有太多關於您的應用程序的信息,我只能猜測。

NH的性能問題通常是由刷新緩存引起的。 在每次查詢之前刷新緩存。 當會話中有很多實體時,可能需要花費很多時間。 請嘗試以下方法:

Log.Info("Flushing");
Session.Flush();
Session.FlushMode = FlushMode.Never;

Log.Info("Query");
var list = Session.Linq<Data>()
    //...
Log.Info("Done");
// for production code, this belongs into a finally block
Session.FlushMode = FlushMode.Auto; 

如果它確實一個刷新問題,您需要在事務中的某些點上手動刷新。 關閉自動沖洗時要小心。 它可能會導致丑陋的副作用。 這是非常具體的交易,我不能說你如何以正確的方式實現它。 你也可以使用StatelessSession ,但對我來說它從來沒有用過(它有一些限制)。 您也可以清除會話,這也要求您確切知道自己在做什么。

如果沒有沖洗問題,則很難跟蹤。 使用Profiler查看它是否實際占用SQL Server查詢中的時間。 它甚至可能是SQL服務器上的緩存問題。 在這種情況下,第一次執行查詢時需要幾分鍾,但第二次只需幾秒鍾。 創建適當的索引可能有所幫 在這里,我停止猜測......

我的假設是有一些攔截器會減慢物體實現或急切加載(即N + 1問題)。

我做了一些測試,甚至30 000個對象也無法減慢獲取對象列表的速度(從本地機器500ms到獲取30000個對象的列表,從遠程數據庫 - 4秒)。

今天一個項目的一個很好的觀點:

我搜索了大約一周的原因,因為我的nHibernate查詢(使用期貨加載某些集合的多標准)需要11秒(在MSSQL探查器中持續時間),如果我在SSMS中執行完全相同的組合查詢,則大約需要2秒。

解決方案是:我激活了一些日志來運行Ayendes profiler。 NHProf dll丟失了,但是:nHibernate中的一些GetRows方法在水合期間觸發日志調用。 差異是:9秒!

我剛剛注釋掉log4net配置調用,延遲幾乎消失了。

我有大約14.000個實例加上60.000個HasMany集合條目。 水合現在需要0.6秒,因為SQL語句需要2秒(這是另一個優化故事)。

並且:我認為水合持續時間和查詢執行持續時間一起顯示在SQL事件探查器“持續時間”列中。

2周前的另一個故事是:SQL分析器中的執行計划與在SSMS中執行查詢時提供的執行計划不同。 原因是,我在nHibernate中使用了OLEDB提供程序。 我切換到ADO連接,執行計划是一樣的。 在查看MS SQL分析器中的某些“協議版本”列時,我發現了這一點。

除了n + 1之外,性能陷阱有很多原因:)

最好的祝願! 邁克爾

有幾個可能的原因:

  • 你將至少4000個對象加載到內存中,給它們加水,NHibernate也必須控制Session和第一級緩存中的每個加載對象
  • 我還沒有看到你的映射,但很可能在某些時候存在某種急切的加載,它也會垃圾郵件發送其他查詢和加載其他對象等等

這些來自我的頭腦,還有我更多。 另外檢查NHibernate的日志級別是否未設置為DEBUG,它是非常詳細的並且可以消耗大量資源。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM