5

コストの高いクエリの一部が「SELECT * FROM ...」を実行するいくつかのSpring JDBCコードをリファクタリングしています-実際に必要な列のチェックを開始し、SELECT x 、 y FROM ..それら. しかし、ResultSetクラスを読んでみると、ほとんどのデータが遅延ロードされているように見えます。ResultSet.next() を実行すると、カーソルがデータベース (このアプリケーションでは Oracle 10g)に移動し、ResultSet.getXX()を実行すると、その列が取得されます。だから私の考えは、「SELECT *」を実行すると必要な列のみを取得しますが、実際にはパフォーマンスに影響はありません。私はこれについて正しく考えていますか?これがあなたを傷つけていると私が考えることができる唯一の場所は、クエリ結果をメモリに保存していて、より多くのメモリを使用する必要があるため、少数の行のみが選択されている場合ですが、実際にはクエリにヒットする列がある場合でも、これは当てはまりません。

考え?

注:これは標準のResultSetにのみ適用されます。 CachedResultSetの動作が異なることはわかっています。

4

6 に答える 6

6

「SELECT *」から「SELECT A、B、C」に移行したことで、必要のない膨大な数の列がない限り、パフォーマンスが大幅に改善された場合は驚くでしょう。

これはすべて、データベース、ドライバー、およびアプリケーションに大きく依存しており、ほとんどの一般化はほとんど意味がありません。

これから得られる唯一の信頼できる答えは、ベンチマークを行うことです。「SELECT *」を試し、「SELECT A、B、C」を試して、追跡する価値のある改善があるかどうかを確認してください。

于 2009-07-24T16:58:20.240 に答える
4

テーブル構造、Oracle のバージョン、関連するインデックスによっては、選択している列のセットを変更すると、クエリ プランが改善され、パフォーマンスが大幅に向上する可能性が十分にあります。ほとんどのクエリでは、パフォーマンス上の利点は最小限に抑えられますが、全体としては、列に明示的に名前を付けることが一般的に推奨されます。

パフォーマンスが向上する最も単純なケースは、オプティマイザーが使用できる「カバーされたインデックス」がある場合に発生します。選択しているすべての列とフィルター処理しているすべての列が単一のインデックスの一部である場合、そのインデックスはクエリの対象インデックスです。その場合、Oracle はテーブルからデータを読み取ることを回避し、インデックスのみを読み取ることができます。

他にもパフォーマンスが向上するケースがあります。最終的な出力に影響を与えない中間結合があるクエリがある場合、オプティマイザーはテーブルの削除を実行できる場合があります。すべての列を選択している場合、その最適化は不可能です。行が連鎖しているテーブルがある場合、列を削除すると、削除された列が存在する追加のブロックをフェッチする必要もなくなります。テーブルに LONG 列と LOB 列がある場合、それらの列を選択しないことも大幅な改善につながります。

最後に、列を削除すると、一般に、オラクルが結果を送信する前にソートおよびハッシュするために必要なスペースの量が削減されます。また、ResultSet がアプリケーション サーバーの RAM にデータを遅延ロードする場合でも、ネットワーク経由で列を遅延フェッチすることはおそらくできません。テーブルからすべての列を選択する場合、JDBC ドライバーは一度に少なくとも 1 行をフェッチする必要があります (ネットワーク ラウンドトリップごとに 10 行または 100 行をフェッチする可能性が高くなります)。また、ドライバーは、データがいつフェッチされ、どの列が要求されるかを知らないため、すべてのデータをネットワーク経由で送信する必要があります。

于 2009-07-24T18:03:27.300 に答える
3

私が働いた環境では、原則として SELECT * は使用されません。スカフマンとアパーキンは、パフォーマンスの向上が小さいことについておそらく正しいと思います。これは、データベース開発者として、取得する列には常に名前を付ける必要があるという強い意見を持っているものの 1 つですが、これには本当の根拠はないかもしれません。

うーん...保守性の観点から、取得している列に名前を付けると、コードを少し自己文書化するのに役立つと主張できると思います。SELECT * は、他の開発者が後で作業するほど多くの情報を提供しません。それと小さなパフォーマンスの利点が余分なタイピングを正当化するかどうかはわかりません。

于 2009-07-24T17:07:36.323 に答える
3

私が関わっていたアプリケーションでは、大規模なデータ ボリューム (および大規模なテーブル サイズ) で、select *からselect x, yに変更することで、わずかなパフォーマンスの向上が得られたことを知っています。ただし、skaffman が行ったように、Oracle の組み込みプロファイラーや外部プロファイラーなどのプロファイリング ツールを使用し、大規模なデータ セットを使用してノイズ (ネットワーク トラフィック、ハード ドライブのスピンアップ、太陽の黒点など) を正規化することを強くお勧めします。など)

于 2009-07-24T17:02:32.650 に答える
3

私はこれについて@skaffmanや他の人たちと一緒です-せいぜいマイナーな進歩です。Oracle がどのようにデータを取得するかを考え、それがブロック I/O であることを思い出すと、クライアントで要求する列に関係なく、データベースはとにかくレコードが見つかったブロック全体を取得します。クライアントが常にレコード全体を取得する場合 (たとえば、SQL*Plus で SELECT * を実行する場合)、パフォーマンスが向上する可能性がありますが、要求した場合にのみデータが送信される状況では、おそらくそれほど多くはありません。

「SELECT *」は、コンパイルされたアプリにとって悪になる可能性があります。テーブルが変更されると、コードが壊れる可能性があります。それが私がそれを使用しない理由です。

編集:ここですべての優れた応答を熟考します:

  1. Justin は、パフォーマンスが大幅に向上する可能性がある特定の状況について、優れた点を指摘しています。
  2. Codemonkey は、自己文書化コードについて優れた点を示しています。
  3. Aperkins と skaffman は、すべての中で最も優れた提案の 1 つを示しています。それを試して、測定し、自分の状況でどのような影響があるかを確認してください。

+1はいたるところにあります...「SELECT *」の使用を推奨している人がまったくいません。必要な正確な列を簡単に指定できる場合は、そのようにコードを修正します。

于 2009-07-24T17:09:49.093 に答える