2

私は NHibernate クエリを持っています (これは EXTJS グリッドにデータを入力しています)

データベースに対して 2 つのクエリを実行します。1 つは (ページング目的で) レコード数を取得するためのもので、もう 1 つはグリッドを埋める上位 N 行を取得するためのものです。

コードから、Select count(*) ステートメントで常に例外が発生します。

NHibernate.Exceptions.GenericADOException: 
Failed to execute multi criteria[SQL: 
 SELECT count(*) as y0_ FROM RecordView this_ inner join ProcessesView 
 process1_ on this_.ProcessId=process1_.Id inner join BusinessModelsView 
 businessmo3_ on process1_.BusinessModelId=businessmo3_.Id inner join BatchesView
 batch2_ on this_.BatchId=batch2_.Id WHERE this_.ProcessId = ?;
] ---> System.Data.SqlClient.SqlException: Timeout expired.  
The timeout period elapsed prior to completion of the operation or the server 
is not responding.

ただし、その正確なクエリを取得して SSMS ウィンドウにドロップして実行すると、1 秒未満で実行されます。

NHibernate は内部で何か「面白い」ことをしていますか? 実行計画/キャッシュの問題はありますか。なぜこれが起こっているのか、私は完全に途方に暮れています。

4

2 に答える 2

2

このエラーが発生するたびに、その理由はロックでした(決してパフォーマンスではありません)。(誤って) 2 つのセッションが開かれました。両方がトランザクションを開始し、そのうちの 1 つがテーブルをロックしました。

問題は、破棄されていないセッション、または「意図しない」シングルトン... 開いたセッションを保持している可能性があります。

この答えは、私が望むほど単純ではありませんが、方向性については確信しています。私も同じことを経験したので(そして罪を犯した)

ところで: Oskar Berggren があなたから発見したように、30 秒のタイムアウトは<property name="command_timeout">30</property>. 確かに、60、120 を提供していただければ、ロックのために十分ではありません。

于 2013-08-23T03:50:25.870 に答える
1

あなたの2つのクエリは、SQL SERVERによって同じ方法で処理されません

  • NH クエリは、テーブルの統計情報とパラメーターの最初の値に基づいて、最初の実行時にコンパイルされています。生成されたクエリ プランは、パラメーター値を考慮せずに、後続のすべての呼び出しに使用されます。

  • あなたの SQL クエリ (ここで、? を実際の値に置き換えたと思います) は、統計と値に基づいて、値ごとに異なるコンパイルを取得します。

最初の NH コンパイルでは、最初の値に対して有効なクエリ プランが生成された可能性がありますが、一般的なケースではそうではありません。

まず、次のことをお勧めします。

  • count(*) よりもわずかに効果的であるため、プロジェクション (メイン テーブル ID など) を当てにして、可能であれば DB がインデックスに対してのみ機能するようにします。
  • クエリに必要なインデックスを見逃さないことを確認します
  • すべてのテーブル統計が最新であることを確認します

これで実行時間が改善されない場合は、この投稿でいくつかのオプションが提供されます (再コンパイルが適切な場合があります): Nhibernate から実行されたクエリは低速ですが、ADO.NET からは高速です

于 2013-08-22T15:08:33.613 に答える