14

SQL Server データベースに対して一連のクエリを実行する Java プログラムがあります。これらの最初のものは、ビューに対してクエリを実行し、約 750k レコードを返します。SQL Server Management Studio 経由でクエリを実行すると、約 30 秒で結果が得られます。ただし、昨夜実行するプログラムを開始しました。今朝確認したところ、このクエリはまだ結果を Java プログラムに返していませんでした。約 15 時間後です。

データベースにアクセスして、やりたいことは何でもできますが、これのデバッグを開始する方法が本当にわかりません。このような状況の原因を突き止めるには、どうすればよいでしょうか。私はデータベース管理者ではなく、SQL サーバー ツール セットに精通していません。

コードはこちら

stmt = connection.createStatement();
clientFeedRS = stmt.executeQuery(StringBuffer.toString());

EDIT1:

しばらく経ち、これは脱線しましたが、この問題は戻ってきました。jdbc ドライバー v 1.2 から 2.0 へのアップグレードを検討しましたが、jdk 1.4 に固執しており、v 2.0 には jdk 1.5 が必要なので、これは初心者ではありません。今、接続文字列のプロパティを見ています。役に立つかもしれない 2 が表示されます。

SelectMethod=cursor|direct
responseBuffering=adaptive|full

現在、レイテンシーの問題により、selectMethod としてカーソルを使用し、responseBuffering のデフォルトがいっぱいになっている状態で実行しています。これらのプロパティを変更すると役立つ可能性がありますか? もしそうなら、理想的な設定は何ですか?オンラインで見つけた情報に基づいて、直接選択法と適応応答バッファリングを使用すると問題が解決する可能性があると考えています。何かご意見は?

EDIT2:

さて、これらの接続文字列パラメーターの両方を変更し、デフォルトの選択方法 (直接) を使用し、responseBuffering を適応型として指定しました。これは最終的に私にとって最適に機能し、私が見ていた遅延の問題を軽減します. すべての助けに感謝します。

4

13 に答える 13

34

同様の問題があり、Java で jdbc 接続を使用すると、非常に単純な要求 (SELECT . FROM . WHERE = .) で 1 行を返すのに最大 10 秒かかりましたが、sqlshell では 0.01 秒しかかかりませんでした。公式の MS SQL ドライバーを使用していても、JTDS ドライバーを使用していても、問題は同じでした。

解決策は、jdbc url でこのプロパティを設定することでした: sendStringParametersAsUnicode=false

MS SQL 公式ドライバーを使用している場合の完全な例: jdbc:sqlserver://yourserver;instanceName=yourInstance;databaseName=yourDBName;sendStringParametersAsUnicode=false;

異なる jdbc ドライバーを使用する場合の手順と、問題に関する詳細情報はこちら: http://emransharif.blogspot.fr/2011/07/performance-issues-with-jdbc-drivers.html

SQL Server では、Unicode をサポートするデータ型と ASCII のみをサポートするデータ型が区別されます。たとえば、Unicode をサポートする文字データ型は nchar、nvarchar、longnvarchar で、ASCII カウンター部分はそれぞれ char、varchar、longvarchar です。デフォルトでは、すべての Microsoft の JDBC ドライバーは、SQL Server で定義された対応する列のデータ型が Unicode をサポートしているかどうかに関係なく、文字列を Unicode 形式で SQL Server に送信します。列のデータ型が Unicode をサポートしている場合、すべてがスムーズです。ただし、列のデータ型が Unicode をサポートしていない場合、特にデータのフェッチ中に重大なパフォーマンスの問題が発生します。SQL Server は、比較を行う前に、テーブル内の非 Unicode データ型を Unicode データ型に変換しようとします。さらに、非 Unicode 列にインデックスが存在する場合、それは無視されます。これにより、最終的にデータ フェッチ中にテーブル全体がスキャンされるため、検索クエリが大幅に遅くなります。

私の場合、検索元のテーブルに 3,000 万件以上のレコードがありました。リクエストを完了するまでの時間は、10 秒以上かかっていましたが、プロパティを適用すると約 0.01 秒になりました。

これが誰かを助けることを願っています!

于 2015-09-30T13:36:56.957 に答える
8

これはあなたの特定の状況には当てはまらないようですが、この問題を探している人に別の可能な説明を提供したいと思いました.

SQL Server で直接実行されたクエリが 1 分かかり、同じクエリが Java 準備済みステートメントを介して 5 分かかるという同様の問題がありました。私はそれが準備されたステートメントとして行われたという事実まで追跡しました。

SQL Server でクエリを直接実行すると、パラメーター化されていないクエリが提供され、最適化時にすべての検索基準が認識されます。私の場合、私の検索基準には日付範囲が含まれていました.SQLサーバーはそれを見て、「その日付範囲は巨大です。日付インデックスを使用しないでください」と判断し、より良いものを選択しました.

Java のプリペアド ステートメントを使用して同じクエリを実行すると、SQL Server がクエリを最適化するときに、まだパラメーター値を指定していないため、使用するインデックスを推測する必要があります。私の日付範囲の場合、狭い範囲で最適化し、広い範囲を指定すると、実行速度が遅くなります。同様に、大きな範囲を最適化して小さな範囲を指定すると、パフォーマンスが再び低下します。

これが実際に問題であることを示すために、実験として、SQL Server の「OPTIMIZE FOR」オプションを使用して何を最適化するかについてのヒントを与えようとしました。小さな日付範囲を使用するように指示したとき、私の Java クエリ (実際には幅広い日付範囲を持っていた) は、実際には以前の 2 倍の時間がかかりました (以前の 5 分とは対照的に、SQL Server の 1 分とは対照的に、10 分) )。最適化する正確な日付を伝えたところ、実行時間はJavaプリペアドステートメント間で同じでした。

したがって、私の解決策は、正確な日付をクエリにハードコーディングすることでした。これは 1 回限りのステートメントだったので、これでうまくいきました。PreparedStatement は再利用することを意図したものではなく、値をパラメーター化して SQL インジェクションを回避することのみを目的としていました。これらの日付は java.sql.Date オブジェクトから取得されているため、日付値にインジェクション コードが含まれていることを心配する必要はありませんでした。

ただし、DOES を再利用する必要があるステートメントの場合、日付をハードコーディングしても機能しません。おそらく、そのためのより良いオプションは、異なる日付範囲 (1 日、1 週間、1 か月、1 年、10 年) 用に最適化された複数の準備済みステートメントを作成することです。必要なのは2つまたは3つのオプションだけです...わかりません)そして、各クエリに対して、時間範囲が実際のクエリの範囲に最もよく一致する1つの準備されたステートメントを実行します。

もちろん、これは日付範囲が均等に分散されている場合にのみうまく機能します。レコードの 80% が昨年のもので、20% が過去 10 年間に分散している場合、「範囲サイズに基づく複数のクエリ」を実行することは最適ではない可能性があります。特定の範囲などに基づいてクエリを最適化する必要があります。試行錯誤でそれを理解する必要があります。

于 2014-10-22T13:39:20.370 に答える
5

JDBC ドライバーが、cusror ベースの接続ではなく、直接接続を使用するように構成されていることを確認してください。不明な場合は、JDBC 接続 URL を投稿できます。

転送専用、読み取り専用の結果セットを使用していることを確認してください (設定しない場合、これがデフォルトです)。

また、最新の JDBC ドライバーを使用していることを確認してください。

これらすべてが機能しない場合は、SQL プロファイラーを見て、jdbc ドライバーがステートメントを実行するときに SQL クエリをキャプチャし、そのステートメントを管理スタジオで実行して、違いがあるかどうかを確認する必要があります。

また、非常に多くのデータをプルしているため、JVM でメモリ/ガベージ コレクションの速度が低下していないことを確認する必要があります (ただし、この場合、時間の不一致は実際には説明されません)。

于 2009-06-07T04:18:04.460 に答える
3

?クエリがパラメーター化されている場合は、パラメーターが欠落しているか、パラメーターが間違った関数で設定されている可能性があります(文字列の setLong など)。問題。

于 2011-01-04T16:05:16.097 に答える
2

これは古い質問であることは知っていますが、この問題を検索したときの最初の結果の 1 つであるため、私にとって何がうまくいったかを投稿する必要があると考えました。SQL Server JDBC ドライバーを使用した場合は 10 秒未満しかかからなかったクエリがありましたが、jTDS を使用した場合は 4 分以上かかりました。ここに記載されているすべての提案を試しましたが、どれも違いはありませんでした。機能した唯一のことは、これを URL ";prepareSQL=1" に追加することです

詳しくはこちら

于 2015-01-02T16:12:00.290 に答える
0

ステートメントのフェッチサイズを調整してみて、カーソルのselectMethodを試してください

http://technet.microsoft.com/en-us/library/aa342344(SQL.90).aspx

mysql を使用した大きな結果セットに問題があり、次のリンクで説明されているように結果セットをストリーミングする必要がありました。

http://helpdesk.objects.com.au/java/avoiding-outofmemoryerror-with-mysql-jdbc-driver

于 2009-06-07T04:20:09.950 に答える
0

これほど多くのデータを引き戻すには、多くの時間が必要になります。いつでもアプリケーションでそれほど多くのデータを必要としない方法を考え出す必要があります。たとえば、データをページングするか、遅延読み込みを使用します。あなたが達成しようとしていることの詳細がなければ、それを言うのは難しい.

于 2009-06-07T02:43:26.750 に答える
0

Management Studio から実行すると高速であるという事実は、不適切にキャッシュされたクエリ プランと古いインデックス (大量のインポートまたは削除など) が原因である可能性があります。SSMS ですべての 750K レコードをすばやく返していますか?

インデックスを再構築してみてください (時間がかかりすぎる場合は、統計を更新してください)。プロシージャキャッシュをフラッシュする可能性があります(これが本番システムの場合は注意してください...):DBCC FREEPROCCACHE

于 2009-06-07T02:53:49.770 に答える
0

これのデバッグを開始するには、問題の領域がデータベースにあるのかアプリにあるのかを判断することをお勧めします。はるかに小さい結果を返すようにクエリを変更しようとしましたか? それが返されない場合は、Java から DB にアクセスする方法をターゲットにすることをお勧めします。

于 2009-06-07T03:53:42.900 に答える
-1

SQLWB と同じくらいの時間がかかりますか? Java のバージョンがはるかに遅い場合は、いくつかのことを確認します。

  1. 転送専用で読み取り専用の ResultSet を使用すると、最高のパフォーマンスが得られます。
  2. MSFT の古い JDBC ドライバーは遅かったことを思い出します。latest-n-greatest を使用していることを確認してください。一般的な SQL Server のものと、SQL 2005 専用のものがあると思います。
于 2009-06-07T03:53:54.117 に答える