5

実稼働環境で実行している Web アプリケーションがあり、ある時点でクライアントがアプリケーションの速度が遅いと不満を漏らしました。

アプリケーションとデータベースで何が起こっているかを確認したところ、この「貴重な」クエリが複数のユーザーによって同時に実行されていたことがわかりました (したがって、データベース サーバーに非常に高い負荷がかかっています)。

SELECT   NULL AS table_cat,
         o.owner AS table_schem,
         o.object_name AS table_name,
         o.object_type AS table_type,
         NULL AS remarks
FROM     all_objects o
WHERE    o.owner LIKE :1 ESCAPE :"SYS_B_0" AND
         o.object_name LIKE :2 ESCAPE :"SYS_B_1" AND
         o.object_type IN(:"SYS_B_2", :"SYS_B_3")
ORDER BY table_type, table_schem, table_name

私たちのアプリケーションはこのクエリを実行しません。Hibernate の内部クエリだと思います。Hibernate がこの非常に重いクエリを実行する理由についての情報はほとんど見つかりませんでした。

本番環境情報: Red Hat Enterprise Linux 5.3 (Tikanga)、JDK 1.5、Web コンテナ OC4J (whitin Oracle Application Server)、Oracle Database 10.1.0.4、JDBC Driver for JDK 1.2 および 1.3、Hibernate バージョン 3.2.6.ga、接続プール ライブラリ C3P0 バージョン 0.9.1。

UPDATE :実際にクエリを実行するのは Hibernate であることを claryfing してくれた @BalusC に感謝します。今、何が起こっているのかについてより良い考えを持っています。ハイバネート セッションを処理する方法を説明します (これは非常に初歩的なものです。より適切に処理する方法について提案があれば、大歓迎です!)

フィルタ (javax.servlet.Filter を実装) があり、開始時 (init メソッド) にセッション ファクトリを構築します (おそらく、これは 1 回だけ発生します)。次に、アプリケーションに送信されるすべての HttpRequest がフィルターを通過して新しいセッションを取得し、トランザクションを開始します。プロセスが終了すると、フィルターを介して戻ってきて、トランザクションをコミットし、休止状態のセッションを強制終了してから、転送ページに進みます (休止状態のセッションは HTTP セッションではうまく機能しなかったため、HTTP セッションには保存しません)。私たちのテスト)。

ここで、私が問題だと思う部分が来ます。私たちの開発環境では、Tomcat 5.5 にアプリを展開し、サービスを開始すると、すべてのフィルターがすぐに1 回だけ開始されます。OC4Jを使用した本番環境では、そのようには機能しないようです。アプリケーションをデプロイし、最初のリクエストが到着したときにのみ、OC4J がフィルタをインスタンス化します。

これは、OC4Jがすべてのリクエストで(または少なくとも複数回、それでも間違っている)フィルタをインスタンス化し、したがってすべてのリクエストでセッションファクトリを作成し、その %&%#%$# クエリを実行すると考えるように導きます。私の問題!

さて、それは正しいですか?フィルタを一度だけインスタンス化するようにOC4Jを構成する方法はありますか?

お時間を割いてご回答いただき、誠にありがとうございました。

4

9 に答える 9

3

それは確かに Hibernate から来ており、具体的にはorg.hibernate.tool.hbm2ddl.TableMetadata. これは、スキーマ (テーブルと列のマッピング) を検証するために使用されたそれぞれの下にあります。どうやら、アプリケーションの起動時に一度だけではなく、生成されたリクエストまたはセッションごとに不必要に実行されているようです。たとえば、すべてのリクエストまたはセッションで Hibernate Configurator を不必要に呼び出していませんか?

于 2010-04-14T22:34:58.140 に答える
2

この問題を回避するために使用した回避策を入れたかっただけです。通常、データベースには多くのスキーマがあり、チェックするオブジェクトの数が多いため、休止状態を使用するアプリケーションで完了するまでに数時間かかります(クエリ自体は高速に実行されますが、実行されましたそれらの非常に多く)。

私が行ったことは、接続されているスキーマのALL_OBJECTSビューをオーバーライドして、データベース内のすべてのオブジェクトではなく、独自のオブジェクトのみを戻すようにすることです。

例えば

ビューALL_OBJECTSをSELECTUSEROWNER、O. * FROMUSER_OBJECTSO;として作成または置換します。

これは最善の解決策ではありませんが、このアプリケーションでは、ALL_OBJECTSビューを使用するものは他にないため、正常に動作し、起動が大幅に速くなります。

于 2012-07-12T14:51:48.273 に答える
2

具体的には、さまざまなデータベースをサポートするソフトウェアを作成する人々が、ソフトウェアをデータベースに依存しない方法でパッケージ化するということです。すなわち。オーバーライドが存在しない場合、jdbc db メタデータ getTables 呼び出しを使用して、接続がまだ有効かどうかを確認します。通常、 select * from dual などで上書きしますが、それが行われていない場合、または使用しているデータベースの種類を具体的に言わない場合、ソフトウェアは、任意の JDBC ドライバーで動作するものを実行するように記述されています。jdbc db metadatabase getTables がそれを行います。

于 2011-10-05T19:25:57.197 に答える
2

@BalusCで指摘されているように、このクエリはスキーマの検証中に実行されます。ただし、検証は通常、SessionFactory(アクティブ化されている場合) の作成時に一度だけ行われます。次のメソッドを明示的に呼び出していますConfiguration#validateSchema(Dialect, DatabaseMetadata)か?


さて、それは正しいですか?フィルタを一度だけインスタンス化するようにOC4Jを構成する方法はありますか?

Open Session In View の実装は問題ないように見えます (このページで提案されている実装に非常に近いものです)。また、サーブレット仕様によれば、デプロイメント記述子の宣言ごとに 1 つのインスタンスのみ<filter>が、コンテナーの Java 仮想マシン (JVMTM) ごとにインスタンス化されます。これが OC4J に当てはまらない可能性は非常に低いため、他に何かあるに違いないと言いたくなりました。

フィルターにログを記録できますか? (古き良きクラスで)SessionFactory静的にするのはどうですか?HibernateUtil

于 2010-04-14T23:13:00.103 に答える
2

何ヶ月も調べた結果、問題は私の Web アプリケーションにあるのではないことがわかりました。問題は、データベースの同じインスタンス (別のユーザー) を使用する他の Oracle Forms アプリケーションでした。

何が起こっていたのかというと、Oracle Forms アプリケーションがデータベース上のレコードをロックしていたため、データベースのほとんどすべての作業が非常に遅くなっていました (私の最愛の Hibernate クエリを含む)。

ロックの理由は、Oracle Forms アプリの外部キーがどれも索引付けされていなかったためです。上司が私に説明したように (彼は理由を発見しました)、ユーザーが Oracle Form アプリケーションでマスター/ディテール関係のマスター レコードを編集しているときに、外部キーのインデックスがない場合、データベースはディテール テーブル全体をロックします。 . これは、Oracle Forms が動作する方法であり、外部キーが参照するフィールドである主キーのフィールドを含む、マスター レコードのすべてのフィールドを更新するためです。

要するに、インデックスなしで外部キーを決して放置しないでください。私たちはこれで多くの苦しみを味わいました。

時間を割いて助けてくれた皆さんに感謝します。

于 2010-07-28T13:55:24.493 に答える
1

10g データベースの sys スキーマは、更新された統計情報で分析されていますか? sys スキーマの固定テーブルの統計を収集しましたか。all_objects に対するクエリは、システムに負担をかけるべきではありません。autotrace/tkprof を介してクエリを実行する場合、リソースの主な使用場所は何ですか。

于 2010-04-13T19:18:11.173 に答える
1

これは、デフォルトの C3PO テスト クエリからのものです。構成でより単純なクエリを指定します。デュアルから「X」を選択します。

于 2010-06-04T21:50:08.707 に答える
1

同じ問題がありました。原因は、Bob Breitling によって説明されたものとまったく同じでした。C3P0 は、接続テストにデフォルトで JDBC API を使用します。

java.sql.DatabaseMetaData#getTables(....)

この動作を変更するには、preferredTestQueryを設定する必要があります。または、C3P0 が hibernate を介して使用されている場合は、hibernate.c3p0.preferredTestQuery

于 2013-07-10T14:48:56.303 に答える
0

このクエリは、DatabaseMetaData を介してデータベース オブジェクト情報を取得するための Hibernate リクエストを実装するために、Oracle JDBC ドライバーから来ていると思います。

このクエリは高すぎてはいけません。少なくとも、私が手元にあるシステムにはありません。all_objects の数と、さらに重要なことは、Explain Plan の行数/バイト数の合計です。

于 2010-04-13T15:53:39.227 に答える