web-dev-qa-db-ja.com

ResultSet:インデックスによる列値の取得とラベルによる取得

JDBCを使用するとき、私はしばしば次のような構造に出くわします

ResultSet rs = ps.executeQuery();
while (rs.next()) {
    int id = rs.getInt(1);
    // Some other actions
}

列の値を取得するためにラベルを使用しない理由を自分自身(およびコードの作成者も)に尋ねました。

int id = rs.getInt("CUSTOMER_ID");

私が聞いた最高の説明は、パフォーマンスに関するものです。しかし、実際には、処理が非常に高速になりますか?信じられませんが、測定を行ったことはありません。私の意見では、ラベルによる検索が多少遅くなるとしても、読みやすさと柔軟性が向上します。
だから誰かが、列ラベルではなく列インデックスによって列値を取得することを避けることについて、良い説明をしてもらえますか?両方のアプローチの長所と短所は何ですか(特定のDBMSに関して)。

50
Rorick

デフォルトではstringラベルを使用する必要があります。

長所:

  • 列の順序の独立性
  • 読みやすさ/保守性の向上

短所:

  • 列名を制御することはできません(ストアドプロシージャを介したアクセス)

どちらを選びますか?

ints?

int i = 1;
customerId = resultSet.getInt(i ++);
customerName = resultSet.getString(i ++);
customerAddress = resultSet.getString(i ++);

または文字列?

customerId = resultSet.getInt( "customer_id");
customerName = resultSet.getString( "customer_name");
customerAddress = resultSet.getString( "customer_address");

また、位置1に新しい列が挿入された場合はどうなりますか?どのコードが好きですか?または、列の順序が変更された場合、どのコードバージョンを変更する必要がありますか?

そのため、デフォルトでstringラベルを使用する必要があります。

46
Martin Klinke

警告:私はここで大騒ぎするつもりです。

99%*の時間は、人々が漠然としたアイデアを持っていることが物事を「より良く」するという、ばかげたミクロの最適化です。これは、数百万のSQL結果で非常にタイトでビジーなループに陥っている場合を除き、完全に無視されます常時(これはまれにしかありませんが)、あなたは決して気付かないでしょう。それを行っていないすべての人にとって、開発者が列のインデックス作成のバグを修正、更新、修正するための時間のコストは、無限にパフォーマンスが悪いアプリケーションのハードウェアの増分コストよりもはるかに大きくなります。

このような最適化をコーディングしないでください。それを保守する人のためのコード。次に、観察、測定、分析、最適化を行います。再度観察し、再度測定し、再度分析し、再度最適化します。

最適化は開発の最終段階であり、最初の段階ではありません。

*図は構成されています。

56
Cowan

それにもかかわらず、答えは受け入れられましたが、ここに、私がまだ提示していない追加情報と個人的な経験があります。

一般的に、可能であれば、列名(リテラルではなく定数が推奨されます)を使用します。これはどちらも明確であり、保守が容易であり、将来の変更によってコードが破損する可能性は低くなります。

ただし、列インデックスの使用があります。場合によっては、これらはより高速ですが、名前*の上記の理由を無効にするほど十分ではありません。これらは、ResultSetsを扱うツールと一般的なメソッドを開発するときに非常に貴重です。最後に、列に名前(名前のない集約など)がないか、重複する名前があるため、両方を参照する簡単な方法がないため、インデックスが必要になる場合があります。

* JDBCドライバーをいくつか作成し、いくつかのオープンソースドライバーの内部を調べましたが、内部では列インデックスを使用して結果列を参照しています。私が扱ったすべての場合において、内部ドライバーは最初に列名をインデックスにマップします。したがって、これらのすべての場合において、列名は常により長くかかることが簡単にわかります。ただし、これはすべてのドライバーに当てはまるわけではありません。

6
Kevin Brock

Javaドキュメントから:

ResultSetインターフェイスは、現在の行から列の値を取得するためのgetterメソッド(getBoolean、getLongなど)を提供します。値は、列のインデックス番号または列の名前を使用して取得できます。一般に、列インデックスを使用する方が効率的です。列には1から番号が付けられます。移植性を最大にするには、各行内の結果セット列を左から右の順序で読み取り、各列を1回だけ読み取ります。

もちろん、各メソッド(名前付きまたはインデックス付き)には場所があります。名前付き列がデフォルトであることに同意します。ただし、膨大な数のループが必要な場合、およびSELECTステートメントがコード(またはクラス)の同じセクションで定義および維持されている場合、インデックスは大丈夫です-選択されている列だけでなく、選択することをお勧めします「SELECT * FROM ...」。テーブルを変更するとコードが破損するためです。

6
Jason

もちろん、列名を使用すると読みやすくなり、メンテナンスが容易になります。しかし、列名を使用すると、裏返しがあります。ご存知のように、SQLでは同じ名前の複数の列名を使用できます。resultSetのgetterメソッドに入力した列名が、アクセスする予定の列名を実際に指しているという保証はありません。理論的には、列名の代わりにインデックス番号を使用することが推奨されますが、読みやすさは低下します...

ありがとう

4
user228462

両方の長所を活用できます!列名を使用する保守性とセキュリティを備えたインデックスの使用速度。

最初-結果セットをループする場合を除き、列名のみを使用します。

  1. アクセスする列ごとに1つずつ、整数変数のセットを定義します。変数の名前には、列の名前を含めることができます。 iLast_Name。

  2. 結果セットループが列メタデータを反復処理する前に、各整数変数の値を対応する列名の列インデックスに設定します。 「Last_Name」列のインデックスが3の場合、「iLast_Name」の値を3に設定します。

  3. 結果セットのループでは、GET/SETメソッドで整数変数名を使用します。変数名は、アクセスされる実際の列名に関する開発者/保守者への視覚的な手がかりですが、値は列インデックスであり、最高のパフォーマンスを提供します。

注:最初のマッピング(つまり、列名からインデックスへのマッピング)は、ループ内のすべてのレコードと列ではなく、ループの前に一度だけ実行されます。

2
Rick Post

Oracleデータベースのこの正確な主題について、パフォーマンスのプロファイルを作成しました。コードには、多数の列と膨大な数の行を持つResultSetがあります。 20秒(!)のうち、メソッドOracle.jdbc.driver.ScrollableResultSet.findColumn(String name)を実行するのに約4秒かかります。

明らかに、全体的な設計に何か問題がありますが、列名の代わりにインデックスを使用すると、おそらく4秒かかります。

2
Marko Ullgren

ラベルの使用はパフォーマンスに大きな影響を与えないと思います。しかし、Stringsを使用しない別の理由があります。または、ints、そのことについて。

定数の使用を検討してください。 int定数を使用すると、コードが読みやすくなりますが、エラーが発生する可能性も低くなります。

定数は読みやすくするだけでなく、ラベル名にタイプミスをすることも防ぎます。そうするとコンパイラはエラーをスローします。そして、任意のIDE価値があればそれを拾います。これは、Stringsまたはintsを使用する場合は当てはまりません。

2
Sietse

JDBCドライバーは、列のインデックス検索を処理します。そのため、ドライバーがルックアップ(通常はハッシュマップで)を行うたびに列名で値を抽出し、列名の対応するインデックスをチェックします。

1
zloster

Mapでラベルを検索する以外に、余分な文字列を作成します。スタック上で発生しますが、それでもコストがかかります。

それはすべて個々の選択に依存し、日付まで私はインデックスのみを使用しました:-)

0
Vinod Singh

パフォーマンスはいずれかのアプローチを選択することを強いるものではないという以前の回答に同意します。代わりに、次のことを検討することをお勧めします。

  • コードの可読性:コードラベルを読むすべての開発者にとって、インデックスよりもはるかに意味があります。
  • メンテナンス:SQLクエリとそのメンテナンス方法を考えてください。 SQLクエリを修正/改善/リファクタリングした後、あなたのケースで起こりそうなこと:抽出された列の順序の変更または結果列名の変更。 (結果セットに新しい列を追加/削除した結果として)抽出された列の順序を変更すると、発生する可能性が高くなります。
  • カプセル化:選択した方法にもかかわらず、SQLクエリを実行するコードを分離し、同じコンポーネントで結果セットを解析し、このコンポーネントのみに列名とインデックスへのマッピングを認識させます(使用することにした場合) )。
0
Cha2lenger

インデックスの使用は、最適化の試みです。

これによって節約される時間は、開発者が必要なデータを検索して、変更後にコードが適切に機能するかどうかを確認するために余分な労力を費やすことによって無駄になります。

テキストの代わりに数字を使用するのは組み込みの本能だと思います。

0
databyss

他のポスターで指摘されているように、列の名前に固執するのは、そうしない強力な理由がない限りです。パフォーマンスへの影響は、たとえばクエリの最適化と比較して無視できます。この場合、メンテナンスは小規模な最適化よりもはるかに重要です。

0
Rober2D2