MySQL
 Computer >> コンピューター >  >> プログラミング >> MySQL

JDBCのPreparedStatementがStatementより高速な理由とは?仕組みをわかりやすく解説

JDBCでSQL文を実行する際、Statementオブジェクトを使用すると、特にINSERT文のような繰り返し実行されるクエリでは、実行のたびにSQL文全体がコンパイルされ、処理されます。ところが、これらのSQL文の間で実際に異なるのは値の部分だけです。

一方、PreparedStatement(プリペアドステートメント)は事前にコンパイルされたSQL文です。クエリは値の代わりにプレースホルダー(?)を使って記述され、一度コンパイルされた後にデータベース側へ保存されます。その後、プレースホルダーに対応する値を後からセットする仕組みになっています。

これにより、同じSQL文を何度も不必要にコンパイル・実行する無駄を排除でき、パフォーマンスが大幅に向上します。

具体例で比較してみよう

データベースにmobile_brandunit_saleというカラムを持つDatasetテーブルがあるとします。Statementオブジェクトを使ってこのテーブルにレコードを挿入する場合、コードは次のようになります。

stmt.executeUpdate("insert into Dataset values('Iphone', 3000)");
stmt.executeUpdate("insert into Dataset values('Samsung', 4000)");
stmt.executeUpdate("insert into Dataset values('Nokia', 5000)");
stmt.executeUpdate("insert into Dataset values('Vivo', 1500)");
stmt.executeUpdate("insert into Dataset values('Oppo', 9000)");
stmt.executeUpdate("insert into Dataset values('MI', 6400)");
stmt.executeUpdate("insert into Dataset values('MotoG', 4360)");
stmt.executeUpdate("insert into Dataset values('Lenovo', 4100)");
stmt.executeUpdate("insert into Dataset values('RedMi', 4000)");
stmt.executeUpdate("insert into Dataset values('OnePlus', 6334)");

executeUpdate()メソッドを呼び出すたびに、引数として渡されたSQL文全体がコンパイルされ、実行されます。よく観察すると、変更されているのはSQL文中の値だけであり、それ以外のクエリ部分は毎回不必要にコンパイルされていることになります。

PreparedStatementを使った場合のコード

同じデータを同じテーブルに挿入する処理をPreparedStatementで書き直すと、次のようになります。

PreparedStatement pstmt = con.prepareStatement("insert into Dataset values(?, ?)");

pstmt.setString(1, "Iphone");
pstmt.setInt(2, 3000);
pstmt.executeUpdate();

pstmt.setString(1, "Samsung");
pstmt.setInt(2, 4000);
pstmt.executeUpdate();

pstmt.setString(1, "Nokia");
pstmt.setInt(2, 5000);
pstmt.executeUpdate();

pstmt.setString(1, "Vivo");
pstmt.setInt(2, 1500);
pstmt.executeUpdate();

pstmt.setString(1, "Oppo");
pstmt.setInt(2, 900);
pstmt.executeUpdate();

pstmt.setString(1, "MI");
pstmt.setInt(2, 6400);
pstmt.executeUpdate();

pstmt.setString(1, "MotoG");
pstmt.setInt(2, 4360);
pstmt.executeUpdate();

pstmt.setString(1, "Lenovo");
pstmt.setInt(2, 4100);
pstmt.executeUpdate();

pstmt.setString(1, "RedMi");
pstmt.setInt(2, 4000);
pstmt.executeUpdate();

pstmt.setString(1, "OnePlus");
pstmt.setInt(2, 6334);
pstmt.executeUpdate();

このコードでは、INSERT文が最初にプレースホルダー(?)付きで準備され、そのクエリは一度だけコンパイルされてデータベースに保存されます。以降は、PreparedStatementインターフェースのセッターメソッド(setString()setInt()など)を使って値を渡すだけで済むため、SQL文の再コンパイルによるオーバーヘッドを回避できます。

PreparedStatementのその他のメリット

パフォーマンス向上以外にも、PreparedStatementには次のような利点があります。

  • SQLインジェクション対策: 値がプレースホルダー経由で安全にバインドされるため、悪意のあるSQLの注入を防げます。
  • 型安全性の確保: setInt()setString()など、型ごとのセッターメソッドにより、データ型の不一致によるエラーを未然に防げます。
  • コードの可読性向上: SQL文とパラメータが分離されるため、保守性の高いコードになります。

このように、大量のレコードを扱うバッチ処理や繰り返し実行されるクエリでは、PreparedStatementを使用することがベストプラクティスとされています。

  1. パスフレーズがパスワードや指紋認証より優れている理由

    パスワードをそのまま「password」にしていた時代を覚えていますか?今でも多くの人が信じられないほど脆弱な方法を使っていますが、ささやかなパスワードも進化を遂げてきました。 現在では、オンラインバンキング、ゲームアカウント、デバイスのロック解除など、あらゆる場面でパスコードやパスフレーズを使用しています。 しかし一部の人々にとっては、これらさえも不要なものとなり、より優れたとされる認証方式への置き換えが進んでいます。ここでは、あえてパスコードとパスフレーズを使い続けるべき理由を解説します。 パスコードとは? 私たちのほとんどは、スマートフォン、メール、その他のアプリやサービスにパスコードや

  2. なぜアップロード速度はダウンロード速度より遅い?原因と改善方法を徹底解説

    インターネットの速度測定をしたことがある人なら、ダウンロード速度に比べてアップロード速度がかなり低いことに気づいたかもしれません。実はこれは珍しいことではなく、世界中でほぼ共通の現象です。Speedtestが発表した2018年7月の世界平均は、下り46.41Mbps、上り22.48Mbpsでした。なぜこのような非対称性があるのでしょうか?一般的に、ISP(インターネットサービスプロバイダ)は2つの点を考慮しています。まず、下り方向の帯域需要が上り方向よりもはるかに多いこと、そして回線が運べるトラフィック量には技術的な上限があることです。非対称であることには実は意味があるDSL、ケーブルテレビ回