27

次のHibernateクエリがあります。

Query query = session.createQuery("from MyHibernateClass");
List<MyHibernateClass> result = query.list();// executes in 7000ms

MySQLで実行されているSQLをログに記録すると、

select 
  myhibernat0_.myFirstColumn as myfirstcolumn92_, 
  myhibernat0_.mySecondColumn as mysecondcolumn92_, 
  myhibernat0_.mythirdcolumn as mythirdcolumn92_, 
  myhibernat0_.myFourthColumn as myfourthcolumn92_ 
from MyHibernateClass myhibernat0_ 
where (1=1);

MyHibernateClassデータベーステーブルの3500行の小さなデータセットでjvmのJavaコードを測定する場合、これには約7000ミリ秒かかります。

一方、Iが次のように直接jdbcを使用する場合:

Statement statement = session.connection().createStatement();
ResultSet rs = statement.executeQuery("select * from MyHibernateClass");// 7ms
List<MyHibernateClass> result = convert(rs);// executes in 20ms

同じSQLがデータベースに入力されているのがわかりますが、jvmのJavaコードで費やされる時間は7ミリ秒です。

MyHibernateClassは、ゲッターとセッターを備えた単純なJava Beanクラスであり、例に示されているような特別なresulttransformerは使用しません。クラスの読み取り専用インスタンスのみが必要であり、休止状態のセッションにアタッチする必要はありません。

Hibernateバージョンを使用したいのですが、実行時間を受け入れることができません。

追加情報:休止状態のログを追加した後、

[2011-07-07 14:26:26,643]DEBUG [main] [logid: ] - 
  org.hibernate.jdbc.AbstractBatcher.logOpenResults(AbstractBatcher.java:426) - 
  about to open ResultSet (open ResultSets: 0, globally: 0)

次のログステートメントの3500が続きます

[2011-07-07 14:26:26,649]DEBUG [main] [logid: ] - 
  org.hibernate.loader.Loader.getRow(Loader.java:1197) - 
  result row: EntityKey[com.mycom.MyHibernateClass#1]

次のような3500のログステートメントが続きます

[2011-07-07 14:27:06,789]DEBUG [main] [logid: ] - 
  org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:130) - 
  resolving associations for [com.mycom.MyHibernateClass#1]
[2011-07-07 14:27:06,792]DEBUG [main] [logid: ] - 
  org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:226) - 
  done materializing entity [com.mycom.MyHibernateClass#1]

これは何を意味するのでしょうか?

最初の実装でHibernateは何をしていますか?どうすればわかりますか?

4

8 に答える 8

32

クラスのすべての属性を持つコンストラクターを追加するとうまくいきました。現在、休止状態のクエリの実行時間は 70 ミリ秒です。以前は、クラスには、引数のないデフォルトのコンストラクターと、エンティティ ID 引数を持つコンストラクターしかありませんでした。

于 2011-07-08T09:07:20.487 に答える
6

新しい情報に基づいて、別の回答を提供する必要があると感じました。違いは、Bean の List プロパティまたは Set プロパティに 1 対多の関連付けが指定されているように見えます。

おそらく、lazy=false遅延読み込みをオフにすることを指定しています。遅延読み込みをオフにすると、すべてのMyHibernateClassエンティティに関連付けられたすべてのレコードがフェッチされるため、実行に時間がかかります。

設定lazy=trueを試してみると、はるかに高速に実行され、エンティティから明示的に要求したときに関連付けられたエンティティのみが取得されます。

于 2011-07-07T13:59:18.090 に答える
5

アプリケーションで Log4j を使用すると、Hibernate に固有のさまざまなログ オプションを設定して、Hibernate の舞台裏で何が起こっているかをよりよく把握できます。

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuration.html#configuration-logging

私の推測では、これは、アプリケーションで最初に HQL クエリを呼び出すときに発生する典型的な初期読み込み時間です。後続の HQL クエリは、この最初のクエリの後、著しく高速になるはずです。

于 2011-07-07T11:37:30.077 に答える
4

私はこのスレッドが古いことを知っていますが、更新するために同じ問題に遭遇しましたが、SQL Server で、ドライバーを使用して Hibernate によって印刷される SQL と SQL Sent が異なることが判明しました。デフォルトで MSSQL ドライバーを使用すると、RPC 呼び出しとしてクエリがストアド プロシージャとして送信されます。これは、ドライバーが MSSQL Standards のクエリ プランを最適化しようとするためです。したがって、次のようなクエリが送信されます。

休止クエリ:

select c.col1,c.col2 from customer c where c.name like @param1 and c.country like @param2

実際のドライバーが送信したクエリ:

@param1=somevalue, @param2=somevalue 
declar sp ....

  select c.col1,c.col2 from customer c where c.name like @param1 and c.country like @param2
go

注: このクエリは、DB を直接リッスンする SQL プロファイラー ツールを介して取得しました

MSSQL での sp_exec 最適化は、キャッシュされる適切なクエリ プランを生成する傾向があることが判明しましたが、これにより、この問題の詳細を知るために「パラメーター スニッフィング」が発生します。

これを克服するために、次のオプションがありました。

  1. HQL をネイティブ クエリに変更し、OPTION RECOMPILE FOR SOME PARAM を追加します

  2. 準備されたステートメントの代わりに直接クエリ値を使用して、param 値の変換がなく、クエリがドライバーによってストアド プロシージャとして変更されないようにします。

  3. ドライバの設定を変更して、ストアド プロシージャを送信しないようにします (MSSQL サーバーのクエリ プランがこのクエリに固有になるため、これはまだ良くありません。これはオプション 2 と同じですが、コードの外にあります)。

オプション 1 と 2 を使用したくありませんでした。これは、ORM フレームワークを使用する目的全体を排除し、今のところオプション 3 を使用することになるためです。

そこで、オプション prepareStatement=false を送信するように JDBC URL を変更しました

これを設定した後、クエリが次のように送信されるという問題がもう1つありました

 Select * from customer c where c.name like **N**'somename' and c.country=**N**'somevalue'

ここでは、エンコード方式を変換することを示す値の前にプレフィックスがあるため、sendUnicode = false への JDBC URL を無効にします。

JTDS ドライバー オプションで行ったのはこれだけです。また、しばらくの間、キャッシュするための第 2 レベルのキャッシュも導入しました。

これが誰かの役に立てば幸いです。何か良い提案があれば教えてください。

于 2015-01-01T00:52:06.113 に答える
1

これは古い質問であることは知っていますが、これが私にとってそれを修正したものです...

hibernate.cfg.xml で、正しい !DOCTYPE があることを確認してください...次のようになります。

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
于 2015-06-18T21:01:18.587 に答える