7

条件APIを使用して動的にまとめられる休止状態のクエリがあります。そのまま実行すると、耐えられないほど遅いクエリが生成されます。

しかし、クエリの先頭に /*+ FIRST_ROWS(10) */ を追加すると、約 1000% 高速になることに気付きました。基準APIでこれを行うにはどうすればよいですか?

私は criteria.setComment(..) を試しましたが、これは無視されているようです。

休止状態のドキュメントでは、3.4.1.7。クエリ ヒントが記載されていますが、「これらは SQL クエリ ヒントではないことに注意してください」と明確に記載されています。

クエリの結果はページ分割されるため、99% のケースで結果 1 ~ 10 が表示されます。

4

4 に答える 4

8

すべての基準クエリで機能する別の一般的なソリューションがあります。
標準のコメントと Hibernate Interceptor を使用して、最終的な SQL をデータベースに変更します。
(私は Hibernate 3.3 で使用しましたが、すべてのバージョンで使用できるはずです。Interceptor の登録は異なる場合があります。)

クエリ コードで次を使用します。

criteria.setComment("$HINT$ push_pred(viewAlias)");

SQL テキストに変更するインターセプターを作成します (これは commons.lang3.StringUtils を使用します)。

public class HibernateEntityInterceptor extends EmptyInterceptor {

@Override
public String onPrepareStatement(String sql) {
    if (sql.startsWith("/* $HINT$")) {
        String hintText = StringUtils.substringBetween(sql, "/* $HINT$", "*/");
        sql = sql.replaceFirst("select ", "select /*+" + hintText + "*/ ");
    }
    return sql;
}

上記は Oracle 用ですが、すべての DBMS で簡単に調整できるはずです。
ヒント マーカー「$HINT$」の定数を作成できる/作成する必要があるかもしれません。
ロギングも行う必要があります (Interceptor の正しい呼び出しを簡単に確認できるようにするため)。簡単にするために、上記では省略しました。

Interceptor を登録する必要があります。春には、これはで行われapplicationContext.xmlます:

<bean id="entityListener" class="your.package.HibernateEntityInterceptor"/>

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="entityInterceptor" ref="entityListener"/>
    [...]

または (Hibernate 3.3 ドキュメントからコピー):

Session スコープのインターセプターは、Interceptor を受け入れるオーバーロードされた SessionFactory.openSession() メソッドの 1 つを使用してセッションが開かれるときに指定されます。

Session session = sf.openSession( new HibernateEntityInterceptor() );

SessionFactory スコープのインターセプターは、SessionFactory を構築する前に Configuration オブジェクトに登録されます。使用するインターセプターを明示的に指定してセッションが開かれない限り、提供されたインターセプターは、その SessionFactory から開かれたすべてのセッションに適用されます。SessionFactory スコープのインターセプターは、スレッドセーフである必要があります。複数のセッションがこのインターセプターを同時に使用する可能性があるため、セッション固有の状態を保存しないようにしてください。

new Configuration().setInterceptor( new HibernateEntityInterceptor() );

于 2016-05-13T13:55:25.337 に答える
7

基準に ProjectionList を追加することで、オラクルのヒントを入れることができました。

ProjectionList proList = Projections.projectionList();
proList.add(Projections.sqlProjection("/*+INDEX_DESC(this_ MY_INDEX_NAME)*/ 1 as MYHINT",
    new String[]{},
    new Type[]{}));
//add properties from your class
proList.add(Projections.property("field1"));
proList.add(Projections.property("field2"));
proList.add(Projections.property("field3"));
c.setProjection(proList);

c.list()List<Object[]>ProjectListの順に返します

于 2011-07-15T23:11:29.010 に答える
5

セッション レベルでオプティマイザ モードを変更できます。

ALTER SESSION SET optimizer_mode = FIRST_ROWS;

クエリの直前にそれをデフォルト値に戻すか(ALL_ROWS)、またはクエリの99%が恩恵を受けるため、スキーマレベルで(ON LOGONたとえばトリガーを使用して)またはインスタンスでさえ変更できますレベル (init パラメータを変更)。

于 2009-08-25T13:39:31.430 に答える
1

問題は、ヒントの構文がコメントではなく、コメントのように見えることです。の前にコメントを追加するのに対し、実際にはSELECTと選択された列の間を移動する必要があります。setComment()SELECT

それ以上に特効薬はありません。 FIRST_ROWSパフォーマンス向上ツールではありません。すべての行を取得するのに時間がかかる場合があります。もちろん、ユーザー向けプログラムでは、最初の 10 行を取得するだけで十分な場合があります。

しかし、どの方法でバウンスしても、Oracle のヒント構文を使用したい場合は、ネイティブ SQL ルートをたどる必要があります。

他に何ができますか?私は (まだ) Hibernate のチューニングの経験があまりありません。私がそのような作業を行ったとき、クエリはテーブル全体から行を取得して、多くのサブタイプを持つオブジェクトをインスタンス化していました。各サブタイプは個別のテーブルでした。Hibernate によって生成されたクエリには多くの OUTER JOIN が含まれていたため、オプティマイザが混乱していました。そのモンスターを、INNER JOIN のみを使用するいくつかの焦点を絞ったクエリ (サブタイプごとに 1 つ) に分割すると、検索時間が 200 分の 1 に短縮されました。

これはすぐには役に立たないかもしれません。しかし、原則は、Hibernate クエリを見て、別のより効率的な方法で実装できるかどうかを確認することです。

于 2009-08-25T11:46:11.257 に答える