• 締切済み

単発PrepareStatementの速さ

PrepareStatementの速度面での有効性を実証した資料を探しています。 今の職場のコーディング規約で、「データベースにアクセスするときはPrepareStatementを使う」となっています。理由は、PrepareStatementはStatementより速いからだそうです。 たしかに繰り返して同一の構造であるSQLを実行する場合、例えば一括登録などの業務であれば有効なのかもしれませんが、コーディング規約は、どんな場合でも使うことになっています。つまり単発の場合でもです。たいていのSQLはほとんど単発が多く、腑に落ちません。 この都市伝説というか、盲目的な信仰は、巷にあるチューニング・プログラミングの書籍・資料でPrepareStatementが速いと紹介されていることが多いのが原因かもしれません。しかし、私が知る限り、「繰り返さない」場合の速度面での有効性を実証した内容を見かけたことがありません。 JDBCのタイプや種類、サーバースペック、RDMS、ネットワーク状況によって異なるかもしれませんが、「単発の場合でもやはり速い」でも、「単発の場合は大した差はない」でも、「単発の場合はむしろ遅い」でも構いません。情報をご提供していただければと思っております。

  • Java
  • 回答数3
  • ありがとう数5

みんなの回答

  • Paul_xxx
  • ベストアンサー率56% (27/48)
回答No.3

速度だけではなく、SQLインジェクション等の セキュリティ対策に対しても有効であるかと思いますよ。

参考URL:
http://www.atmarkit.co.jp/fjava/rensai2/jspservlet10/jspsevlet10_2.html
run34ricky
質問者

お礼

回答ありがとうございます。また、返答が遅くなり申し訳ありません。 他のメリットも理解しております。ただ、今回は速度について確認したかったのです。他のメリットを持ち出すと、デメリットも持ち出したりして、論点がぼやけるおそれがありますので、速度面をとりたいと思っております。 私が、PrepareStatementのデメリットの1つとして感じているのは、実行するSQL文をStringで取得するメソッドが見あたらません。よって実行前にSQL文をログに出力できず、SQL例外が発生したときにどんなSQLだったのか確認しづらいなぁと思っています。

  • Bonjin
  • ベストアンサー率43% (418/971)
回答No.2

>PrepareStatementはStatementより速いからだそうです。 逆に単発実行の場合にPreparedStatementの方が速くなるまたは同程度であることを実証してもらえばいいのではないでしょうか? 規約を決める側が証明できなければお話になりませんよね? ちなみに私は規約としてPreparedStatementを盛り込むならば、速度面ではなく可変的な値を使うときなどのバグを減少できる点だと思っているのですが・・・ 他の観点から書かせてもらいますと、 StatementやResultSetなどはSunが決めたインターフェースであって実装するのはDBMSの各ベンダー等であることはご存じだと思いますが、では全てが本当にその通りに実装されているのでしょうか?全部の全部を解析したわけでもないのにインターフェースだけで「速い」と決め付けている規約作成側には少なからず不信感を覚えます。

run34ricky
質問者

お礼

早速の回答ありがとうございます。また、返答が遅くなり申し訳ありません。 規約担当者も、もともと他のプロジェクトを使っていたモノを流用したり、雑誌などのうたい文句をそのまま反映したり、と検証していない節があります。規約の作成権はあっても、それを修正する権限と時間がないように見受けます。 今のプロジェクトは既に進行していて、私は途中参画しているため、規約変更はできませんが、次回のプロジェクトでぶつけようと思います。

  • T0ngT0ng
  • ベストアンサー率40% (8/20)
回答No.1

確かに、単発で実行する場合、効果はないと思います。 ですが、逆に遅くなるということもないと思います。 (SQLの解析を先にやるだけですので) ですので、コーディングの規約として考えた場合、統一しておいたほうがよい、 としても不自然ではないと思います。 なぜなら ・コーディングのたびにどちらを使うべきか迷う必要がない。  ※コーディングレビュー時等第3者でも判断に困らない。 ・コードの修正/流用時に繰り返す必要が出てきても対応可能。 だからです。 蛇足かもしれませんが、参考URLの記事(少し古いですが)によれば、 Web開発等で使用する場合なら、単発でもパフォーマンスをあげられそうですね。

参考URL:
http://www.atmarkit.co.jp/fjava/rensai2/webopt11/webopt11.html
run34ricky
質問者

お礼

早速の回答ありがとうございます。また、返答が遅くなり申し訳ありません。 参考URLは、APサーバーに依存する話ですが、主要サーバーに、そのメリットがあれば、速度面の優位性は保たれますね。 また、製造担当者に悩ませないメリットは確かにあります。ただ、今の職場は、PrepareStatementを含めて、何かと規約が硬直ぎみで、製造担当者の技量を狭めていたり、性能が引き出せずにいて困っています。次回のプロジェクトでは、柔軟性を求めたいと思います。

関連するQ&A

  • MySQLのチューニングについて

    チューニングについて質問です。 1. SQLの純粋な実行速度を知るにはどうしたらよいか 2. SQLの叩かれる回数が多い場合にレスポンスが遅くなるのはどう対応すればよいか 1については、純粋に単体での実行時間が知りたいのですがSQLのキャッシュが残っているせいか、高速に処理されてしまうために、なかなか正確な時間が分かりません。 どのようにしたら単体での実行速度を計測できるのでしょうか。 2については、SQL単体ではなかなかの速度が出せているのに、そのSQLが短時間に大量に呼び出される場合に、サーバの負荷があがり、レスポンスが遅くなってしまう場合はどう対処すればよいのかを聞きたいです。 よろしくお願い致します。

    • ベストアンサー
    • MySQL
  • 計算ができません。

    JDBCでプログラミングをしています。 テーブルからデータを取り出して、 計算をして、違うテーブルに格納するプログラムを作っているのですが、 計算した値が出てきません。 どこがおかしいのかわかりません。 ご指摘をお願いします。 プログラムの一部です。 ********** Connection connection =DriverManager .get connection(XXXX); Statement statement = connection.createStatement(); ResultSet rs5 = statement .executeQuery("salect ENAME, JOB, SAL, COMM from EMP where JOB = 'PRESIDENT'"); while(rs5.next()) { String ename = rs5.getString(1); String job = rs5.getString(2); long sal = rs5.getLong(3); sal = round(sal*9.00+(sal*0,19)); long comm = rs5.getLong(4); String sql ="insert into BONUS values(?,?,?,?)"; PreparedStatement prestmt = connection.prepareStatement(sql); int result = 0; for(int i = 0; i<1; i++) { prestmt.setString(1.ename); prestmt.setString(2.job); prestmt.setLong(3.sal); prestmt.setLong(4.comm); result += prestmt.executeUpdate(); } } rs5.close(); statement.close(); connection.close(); ********** プログラムの中でSALの計算をしているのですが、 結果として出てくるのが元の値です。 計算結果をどうしたら出せるのか教えてください。

  • PreparedStatement と Statement について

    PreparedStatement と Statement について教えてください。 PreparedStatement は、 「実行環境にもよるが、Statement より、処理速度が40%~50%ほど短縮される」という記述があったのですが、その逆のケースはありませんでしょうか? [参考URL]  http://el.itlab-school.jp/index.cgi/javamysql Statement の処理が、 PreparedStatement より、早くなる、そんな状況はないでしょうか? また、Statementより、 PreparedStatement方が、基本的にはの方が処理が早いという特徴から、気になるところがあるのですが 実際のWebアプリケーションを作成のときは、 レスポンス速度も考慮し「PreparedStatementにてSQL文を発行するべきでしょうか?」(例え、"?"を使用することがなかったとしても) PreparedStatementを使用せずに、 Statementを使用した方がいい場合、という状況はあるのでしょうか?

    • ベストアンサー
    • Java
  • JDBCについて

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import com.mysql.jdbc.PreparedStatement; import com.mysql.jdbc.Statement; public class DBtest { public static void main(String[] args){ try { Connection con = null; PreparedStatement ps = null; String url = "jdbc:mysql://localhost/address"; String user = "test"; String password = "pass"; con = DriverManager.getConnection(url, user, password); Statement st = (Statement) con.createStatement(); Statement st2 = (Statement) con.createStatement(); String sql = "SELECT * FROM data2"; ResultSet rs = st2.executeQuery(sql); try { System.out.println("ok"); // ここでクエリを実行 while(rs.next()){ System.out.println(rs.getString("name")+rs.getString("age")); } //氏名入力 System.out.println("氏名を入力してください。"); BufferedReader na = new BufferedReader(new InputStreamReader(System.in)); String Na = na.readLine(); String ins = "INSERT INTO data2(name,age)VALUES('?',20)"; ps = (PreparedStatement) con.prepareStatement(ins); ps.setString(1,Na); ps.executeUpdate(); //INSERT実行 int rs2 = st2.executeUpdate(ins); System.out.println(rs2); } catch (IOException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } finally { // 直前の try ブロックに入ったら、ここは必ず実行される con.close(); } } catch (SQLException ex) { System.out.println("SQLException: " + ex.getMessage()); System.out.println("SQLState: " + ex.getSQLState()); System.out.println("VendorError: " + ex.getErrorCode()); // 接続できない時 } } } 現在javaでmysqlに接続してDB内の検索や追加等を行うものを作成しています。 現状は入力されたものをDBに追加することまでできましたが 検索で 入力された値がDBの中に一致する、または部分一致したものを表示させるやり方がわかりません

    • ベストアンサー
    • Java
  • Java環境で使用するAccessデータベースについて

    以下の様な開発環境でシステムを構築しています。 OS:windowsXP DB:Microsoft Access 2002 j2sdk:1.4.2_05 Tomcat:4.1.30 Web上で登録画面を表示、登録されたデータをサーブレット経由でDBに登録しようとしたところ、「パラメータが少なすぎます」というメッセージが出て登録できませんでした。 DBおよびSQL構文のエリア名の記入ミスも調べましたが問題ない模様です。 AccessのODBCドライバ(MDAC2.5)について調べたところ、MDAC2.5を使用したSQL文では二重引用符(”)を文字列リテラルとして使用できないようです。 この問題を回避するよい方法があれば、ぜひ教示願います。 <コーディング内容> //postされた内容を受け取る String wkkanri = request.getParameter(“kanri_No”); String wkroom = request.getParameter(“room_No”); ------------------------------------------------- //ドライバクラスのロード、DB接続 Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”); Connection con = DriverManager.getConnection(“jdbc:odbc:syataku”); Statement stmt = con.createStatement(); //insert用sql文の発行 String sql = “insert into kihon(kanri_No,room_No) values(wkkanri,wkroom)”; Stmt.executeUpdate(sql);

  • ORACLEはXPとVISTAどちらが動作は速いでしょうか

    お世話になります。 環境 XP ORACLE 9i     VISTA ORACLE10 コーディングは、できるだけ変えずに動かした場合どちらが処理速度は速いでしょうか。(マシンスペックは同じものを使用した場合) 使用している命令や9用にチューニングしているか、XPをVISTAにアップグレードしたか、VISTAをXPにダウングレードしたかで変わるとは思うのですが何か目安となるものをご存知でしたら教えて頂きたくよろしくお願いします。

  • Tomcat上で動くサーブレットがデータソースを見つけられない

    こんにちは。 以前にjdbcとサーブレットに関する質問をさせてもらった者です。 以前の質問に対する皆さんのご回答のおかげで、以前の問題は解決し、あとは自分でなんとかすると言っていたのですが… 新たな問題に直面しまして自分なりに努力はしたのですが、やはり解決には至らず、結局皆さんの助言を賜りたくて来ました。 JDBC-ODBCブリッジドライバを使って、Oracle10gデータベースを問い合わせるTomcat6.0サーバ上で動作するサーブレットの構成を行っています。 データベース、サーバ、サーブレットは同一のハードウェア内で動作しています。 環境は以下の通りです。 データベース : Oracle10g 使用ポート番号:8081 データソース名:OracleInXE サーバ : Tomcat6.0 使用ポート番号:8080 接続API : jdbc-odbcブリッジドライバ データベース接続部のソースを一部抜粋します。 ~ Connection connection = null; Statement statement = null; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); connection = DriverManager.getConnection("jdbc:odbc://localhost:8081/OracleInXE",user.getName(),user.getPassword()); statement = connection.createStatement(); ~ SQLExceptionで取得したスタックトレースの内容を記述します。 [Microsoft][ODBC Driver Manager] データ ソース名および指定された既定のドライバが見つかりません。 at sun.jdbc.odbc.JdbcOdbc.createSQLException(Unknown Source) at sun.jdbc.odbc.JdbcOdbc.standardError(Unknown Source) at sun.jdbc.odbc.JdbcOdbc.SQLDriverConnect(Unknown Source) at sun.jdbc.odbc.JdbcOdbcConnection.initialize(Unknown Source) at sun.jdbc.odbc.JdbcOdbcDriver.connect(Unknown Source) at java.sql.DriverManager.getConnection(Unknown Source) at java.sql.DriverManager.getConnection(Unknown Source) at employeeManagementSystem.Query.authentication(Query.java:59) at Run.main(Run.java:33) しかし上記の場合だとSQLExceptionga発生し、"データ ソース名および指定された既定のドライバが見つかりません。"と表示されます。 サーブレットがデータソースを見つけられない原因は何でしょうか。 あと、その解決法や、役立つ情報があれば教えて下さい。 宜しくお願いします。 データソースのURLが間違っているのでしょうか。 また、ドライバクラスとURL表記の組み合わせも色々あるみたいでややこしいです… 何か、小さい事に引っかかっている感じがするのですが。

    • ベストアンサー
    • Java
  • 【チューニング】インデックスとヒント句の違い

    いつもお世話になっています。 oracle9iR2を使用しています。 速度アップのためチューニングが必要なsqlが指摘されたのですが、 あるカラムにインデックスを作成すべきとの指摘がありました。 インデックスを作成するだけである程度改善される場合もあるのでしょうか? それともインデックス作成後、対象のsql/に、*+INDEX・・・ などのようにSQLにヒント句を記載してこそ効果を発揮するものなのでしょうか? 質問がまとはずれでしたら申し訳ありません。 どなたかご教授お願いします。

  • チューニング対象のSQLの見つけ方・「遅い」SQLの目安

    質問はずばり、SQLを「遅い」と判断する具体的な処理時間・判断基準は? です。前提は比較的単純なSELECT文とさせてください。 パフォーマンスチューニングする際などにはSTATSPACK reportをみてとりあえず 1回あたりの処理時間が遅いSQLやStatement Totalの 処理時間が長いSQLを ターゲットにしていくものだと思います。 しかし極端な話、単に上位といってもトップのSQLの処理時間が1msec以下だったらそもそも パフォーマンスチューニングは一切必要ないはずです。 逆にTOP10以下でも単純なSQLなのに1秒以上処理時間のかかるものが多数あった場合には 何か問題があるはずと考えチェックしていくべきだと思います。 もちろん、データ数や結合テーブル数・条件の複雑さによって一概には言えないことはわかります。 しかし、大体の目安というものはあるべきかと思います。 私のなんとなくの判断基準は 「軽めのものは0.03秒程度、重めでも0.2秒程度」かなーと思っています。 経験的なものでまったく根拠はありません。経験も大してありません。 なので、もう少し根拠のある数字もしくはもう少し経験のある方のご意見 を伺いたいと思い質問させていただきます。 よろしくお願いします。

  • Prepared Statementがおかしい

    MySQLに対して検索する Prepared Statement について質問します。 現在、 Google App Engine(GAE) で動いていたJavaのアプリケーションを Amazon Web Service(AWS) に移動すべく、ソースの見直しを行っています。 以下のソースを走らせると、GAEのローカルテスト環境では動くものの、AWSのローカルテスト環境では エラーが出てしまいます。 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html"); response.setContentType("charset=utf-8"); PrintWriter out = response.getWriter(); try{ /** データベースへの接続を保持するConnectionクラス */ DBAccess dba = new DBAccess(); Connection conn = dba.getConnection(); PreparedStatement pstmt = null; int staffId = Integer.parseInt(request.getParameter("staffId")); String staffName = request.getParameter("staffName"); String staffSort = request.getParameter("staffSort"); String sql = "UPDATE first_tbl_staff SET staffName=?, staffSort=? WHERE staffId=?"; pstmt = conn.prepareStatement(sql); pstmt.setString(1, staffName); pstmt.setString(2, staffSort); pstmt.setInt(2, staffId); System.out.println("sql================" + sql); int count = pstmt.executeUpdate(sql); ※※※←ここで落ちる if(count == 1){ String res = "["; res += "{\"staffId\":\"" + staffId + "\"}"; res += "]"; out.println(res); } pstmt.close(); conn.close(); } catch(Exception e){ System.out.println("例外発生:" + e ); }finally{ } } } コンソールを見ると、以下のプリントアウト文と例外を出しています。 sql================UPDATE first_tbl_staff SET staffName=?, staffSort=? WHERE staffId=? 例外発生:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?, staffSort=? WHERE staffId=?' at line 1 簡単なUPDATE文ですので、文法的にも間違いないと思いますが、何度やってもGAEでは動作しますが、AWSではエラーとなってしまいます。 それぞれの開発環境ですが、同一のマシン(Windows7 32bit)に2つのEcripseを載せています。 【GAE】 ・Eclipse3.7 ・Java 6 ・Jetty? ・App Engine SDK ・MySQL5.5.27  ・jdbcドライバ:mysql-connector-java-5.1.26-bin.jar 【AWS】 ・Eclipse4.3 ・Java 7 ・Tomcat 7 ・AWS SDK ・MySQL5.5.27  ・jdbcドライバ:mysql-connector-java-5.1.26-bin.jar MySQLはローカルの同一のDB/テーブルを見に行ってます。 UPDATE文でエラーが出ますが、INSERT文でも同様にGAEでは通るのですがAWSではエラーになります。 因みにPrepared Statementオブジェクトではなく Statementオブジェクトを利用すると問題なく動きました。 丸1日かかっていろいろ環境を変えたりしていますが、Prepared Stateオブジェクトを利用すると、SQLの中味が 捉えにくく解決できない状況です。 どなた、ヒントになるようなことがおわかりでしたら、ご指導下さい。 よろしくお願いします。

    • ベストアンサー
    • Java