2009-08-06 7 views
2

テーブルから1列(600万行)を選択するJava Webアプリケーションがあり、CPU時間がかかる。このselect(SELECT id FROM mytable WHERE filename = 'unique_filename')は、クエリブラウザで実行すると時間が大幅に短縮されます。なぜSQLでの選択でJavaでCPU時間がかかるのですか?

これはどうしてですか?
どこでボトルネックを探す必要がありますか?データベースオブジェクトは、接続オブジェクトを受信するためのDriverManagerを使用

ResultSet rs = null;  
PreparedStatement stmt = null; 
Connection conn = null; 
Integer myId=null; 
String myVeryUniqueFileName = strFromSomeWhere; 
try 
{ 
    conn = Database.getConnection(); 
    stmt = conn.prepareStatement("SELECT id FROM mytable WHERE filename = ?"); 
    stmt.setString(1, myVeryUniqueFileName); 

    rs = stmt.executeQuery(); 
    if (rs.next()) 
    { 
     myId= new Integer(rs.getInt(1)); 
    }    } 
    if (rs.next()) 
    { 
     throw new DBException("Duplicate myId: " + myId); 
    } 
    return myId; 
} catch (Exception e) { 
    // handle this 
} 


1.Javaコード:

データベースは Javaコンテナが(sqljdbc 1.2)のTomcat 5.5

詳細あるMSSQL 2005規格
であります。

2.SQLテーブルのカラム数は約30です。

CREATE TABLE [dbo].[calls]( 
    [id] [int] NOT NULL,  
    ...  
    [filename] [varchar](50) NOT NULL, 
    ...  
CONSTRAINT [PK_xxxxxxxxxxxx] PRIMARY KEY CLUSTERED  
( 
    [id] ASC  
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],  
CONSTRAINT [UQ_xxxxxxxxxxxx] UNIQUE NONCLUSTERED  
(  
    [filename] ASC  
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]  
) ON [PRIMARY]  

ファイル名の列が一意であるため、結果セットはallways 1またはnullです。

+1

あなたがCPU時間を言うとき、あなたは、Javaが使用するCPUを意味していますアプリケーションまたはデータベースサーバーで使用されるCPUそれらは2つの異なるマシンにありますか? –

+0

TomcatとMSSQLは同じサーバーにありますか?あなたのJavaアプリケーションは、どのオブジェクトに6百万のID値を格納していますか? Javaと.NETはメモリ内の各オブジェクトを作成して破壊する時間を必要とします.600万のオブジェクトを作成する必要がある場合は、かなりの時間がかかります。 –

+0

これは本当の質問ではありません。それはあまり詳しくはないが、OPはまだそれを修正するかもしれない。 – ChssPly76

答えて

2

もっとスマートな開発者の助けを借りて、私はこの問題を解決することができました。私はPreparedStatement(aricle)を悪用していたことが分かります。これに基づき

私は、Javaコードを変更:このdababase負荷が13%、平均70%から低下した後

ResultSet rs = null;  
Statement stmt = null; 
Connection conn = null; 
Integer myId=null; 
String myVeryUniqueFileName = strFromSomeWhere; 
try 
{ 
    conn = Database.getConnection(); 
    stmt = conn.createStatement() 
    // 
    rs = stmt.executeQuery("SELECT id FROM mytable WHERE filename = '" 
         + myVeryUniqueFileName + "'"); 
    if (rs.next()) 
    { 
    myId= new Integer(rs.getInt(1)); 
    }    
    if (rs.next()) 
    { 
    throw new DBException("Duplicate myId: " + myId); 
    } 
    return myId; 
} catch (Exception e) { 
    // handle this 
} 

0

説明する現象は、誤ってキャッシュされたクエリプランによって発生することがよくあります。

インデックスを再構築するか、統計情報を更新してください。

+0

私は、クエリプランがインデックスの再構築に直接関係しているとは言いません。それはあなたが暗示しているようです。 –

0

おそらくステートメントを使用していますが、準備済みステートメントは使用していません。ステートメントはプリコンパイルされてキャッシュされないため、クエリオプティマイザは毎回作業を行う必要があります。プリペアドステートメントを使用すると、クエリを実行するための最良の方法が見つけられ、格納されます。あなたが次回にそれを使用するときには、それが既に持っている実行計画だけであなたの結果を得る良い方法を試してみるのは面倒ではありません。

1

このクエリを実行している場所でJavaコードを投稿して結果を取得できますか? が大幅に長く取ることを見えるようにJavaコードを引き起こし

可能性のある要因は以下のとおりです。

  1. あなたのクエリが多数のレコードを返し、クエリブラウザだろう唯一のショーのに対し、Javaでそれらすべてを取得しようとしています最初の100(その番号が何であっても)、要求に応じて他のものをロードします。
  2. さまざまな時間を比較しています。たとえば、クエリーブラウザに表示される「query took X ms」のように、Javaが接続を取得するまでに時間がかかります。
  3. あなたのオブジェクト(結果を保持している)は、作成するのに費用がかかります。または、入力されたシーンの裏側で何らかの処理を行っている可能性があります。
1

特にMSSQL 2005とは話せませんが、バインド変数を使用するプリペアドステートメントと、値が埋め込まれている同等のステートメントとの間に実行計画に違いがあります。

この理論をテストするには、バインドパラメータを削除し、代わりにJavaのSQLクエリを実際のファイル名(引用符で囲んだもの)と連結します。あなたはリンゴとリンゴを比較しています。

また、発生しているCPU時間の差を表示すると便利です。それは数桁または100%未満ですか?

関連する問題