どちらが高速/最高ですか?SELECT *またはSELECT column1、colum2、column3など


166

SELECT *SQLコマンドを作成する場合、SELECT特に必要な列に対してより効率的であるため、SQLコマンドを使用するのは一般に悪い習慣だと聞きました。

SELECTテーブルのすべての列が必要な場合、使用する必要があります

SELECT * FROM TABLE

または

SELECT column1, colum2, column3, etc. FROM TABLE

この場合、効率は本当に重要ですか?SELECT *あなたが本当にすべてのデータを必要とするならば、私は内部的にはより最適だと思いますが、私はこれはデータベースの本当の理解なしで言っています。

この場合のベストプラクティスを知りたいです。

UPDATE:私はおそらく、私は本当にだろう唯一の状況ように指定する必要がありますしたい Aを行うにはSELECT *私はすべての列が常に新しい列が追加された場合でも、検索される必要があります知っている一つのテーブルからデータを選択していたときです。

しかし、私が見た応答を考えると、これはまだ悪い考えのように思わSELECT *れ、私がこれまで考えたより多くの技術的な理由のために使用されるべきではありません。




1
はい、それはそれらのほとんどの複製です。
ジョージストッカー

回答:


168

特定の列を選択する方が良い理由の1つは、SQL Serverがテーブルデータをクエリするのではなく、インデックスからデータにアクセスできる可能性が高くなることです。

これについて私が書いた投稿は次のとおりです 。選択クエリがインデックスカバレッジが悪いという本当の理由

また、データを使用するコードは、将来テーブルスキーマに加えた変更に関係なく、同じデータ構造を取得するため、変更の脆弱性も少なくなります。


3
+1。参照されているすべての列が単一のインデックス(「カバリングインデックス」)に存在する場合、金を打ったことになります。
Ian Nelson、

22
それは彼の質問に対する答えではありません-「テーブルのすべての列をSELECTする必要がある場合...」-その場合、* vs col1、..、colnは問題ではありません(ただし、プログラマの時間はかかります)。 *が短いので!)
Matt Rogish

3
選択リストはコントラクトの形式であるため、SQLがストアドプロシージャ内にある場合は特に重要です。
Eric Z Beard

4
Jonの言うことは完全に正しいことであり、非常に有効な点ですが、AS ASSKEDの質問は、すべての列をすでに求めているかどうかという点に同意する必要があります。質問のこの部分のために、実際の問題はスキーマの変更に直面して脆弱であることです。
IDisposable

1
@MattRogish sirあなたは正しくそれを手に入れました、vs何千もの行があり、(WHERE句で)インデックスを指定してSELECTを実行している間、これら2つのメソッド(* all_column_names)の間にパフォーマンスの違いはありますか?
santosh 2018年

59

与えられたあなたのあなたがいることを仕様しているすべての列を選択し、ほとんど差があり 、この時点では。ただし、データベーススキーマは変更されることに注意してください。使用SELECT *すると、テーブルに新しい列が追加されますが、コードはその新しいデータを使用または提示する準備ができていません。これは、予期しないパフォーマンスと機能の変更にシステムをさらしていることを意味します。

これを小さなコストとして却下してもかまいませんが、不要な列は次のようにする必要があることに注意してください。

  1. データベースから読み取る
  2. ネットワーク経由で送信
  3. プロセスにマーシャリング
  4. (ADOタイプのテクノロジの場合)メモリ内のデータテーブルに保存
  5. 無視して破棄/ガベージコレクション

アイテム#1には潜在的なカバーインデックスの排除、データページの読み込み(およびサーバーキャッシュのスラッシング)の原因、行/ページ/テーブルのロックの発生など、他の方法では回避できる可能性のある多くの隠れたコストがあります。

これを、列を指定することによる潜在的な節約と対比*し、唯一の潜在的な節約は次のとおりです。

  1. プログラマーはSQLを再訪して列を追加する必要はありません
  2. SQLのネットワーク転送はより小さく/より高速です
  3. SQL Serverクエリの解析/検証時間
  4. SQL Serverクエリプランキャッシュ

項目1の場合、実際には、とにかく追加する可能性のある新しい列を使用するようにコードを追加または変更するので、それは洗浄です。

項目2の場合、違いがパケットサイズやネットワークパケットの数を変えるのに十分ではありません。SQLステートメントの送信時間が主な問題となるポイントに達した場合は、最初にステートメントの割合を減らす必要があるでしょう。

項目3の場合、*とにかく展開を行う必要があるため、節約はありません。つまり、テーブルスキーマを参照する必要があります。現実的には、列を一覧表示してもスキーマに対して検証する必要があるため、同じコストがかかります。つまり、これは完全な洗浄です。

あなたが特定の列を指定するときの項目4については、クエリプランのキャッシュがより大きな得ることができる唯一のあなたは(あなたが指定したものではありません)列の異なるセットを扱っている場合。この場合は、あなたがしたいですか、必要に応じて別の計画をしたいので、異なるキャッシュエントリを。

したがって、質問を指定した方法が原因で、スキーマの最終的な変更に直面した場合の問題の回復力が低下します。このスキーマをROMに書き込んでいる場合(それが発生する場合)は、*完全に許容可能です。

ただし、私の一般的なガイドラインでは、必要な列のみを選択する必要があります。つまり、すべての列を要求しているように見えることもありますが、DBAとスキーマの進化により、クエリに大きな影響を与える可能性がある新しい列が表示される場合があります。

私のアドバイスは、常に特定の列を選択する必要があるということです。何度も上手にできるようになることを忘れないでください。そのため、正しいことをする習慣を身に付けてください。

コードを変更しなくてもスキーマが変更される理由について疑問がある場合は、監査ログ、有効/有効期限、およびコンプライアンスの問題のためにDBAが体系的に追加するその他の同様のものについて考えてください。根本的な変更の別の原因は、システムまたはユーザー定義フィールドの他の場所でのパフォーマンスの非正規化です。


3
「実際には、とにかく追加する可能性のある新しい列を使用するようにコードを追加または変更するので、それは洗浄です。」-コード内の名前で各列を手動で読み取る場合のみ。自動マッピングを使用している場合、これは当てはまりません。この問題は重大になります。
Josh Noe、

36

必要な列のみを選択する必要があります。すべての列が必要な場合でも、SQLサーバーがシステムテーブルに列を照会する必要がないように、列名をリストすることをお勧めします。

また、誰かがテーブルに列を追加すると、アプリケーションが壊れる可能性があります。プログラムは予期しない列も取得し、それらの処理方法を知らない可能性があります。

これとは別に、テーブルにバイナリ列がある場合、クエリははるかに遅くなり、より多くのネットワークリソースを使用します。


6
*を使用することで、DBに追加の作業が追加されます。それが私が考えていなかった理由の1つです。
Ankur

1
ミスを早期に解消/キャッチするリスクの+1。効率についての議論は妥当だと思いますが、YAGNIです。
nailitdown

6
SQLサーバーは、 "col1"が指定されたテーブル(クエリシステムテーブル)にあるかどうかを検証または確認する必要はありませんか?
Patrick

3
最大のパフォーマンスヒットは、おそらくインデックス作成に関連しています。探している列がデータを見つけるために使用されるインデックスの一部である場合、サーバーはその場所でデータをフェッチします。select*を実行すると、ほとんどの場合、ブックマークルックアップと呼ばれる処理を実行する必要があります。スキャンして、必要のない残りの基礎データを見つけます。
Cobusve

3
@パトリック-スポット。*避けるべき多くの理由がありますが、それはそれらの1つではありません。
マーティン・スミス

31

select *悪いことには4つの大きな理由があります。

  1. 最も重要な実用的な理由は、列が返される順序をユーザーに魔法のように強制することです。明示的にすることをお勧めします。これにより、テーブルの変更からも保護されます。

  2. 使用している列名が変更された場合、存在しない(または名前が変更された)列を使用しようとしているときよりも、(SQL呼び出しの時点で)早期にキャッチすることをお勧めします。 )

  3. 列名をリストすると、コードがはるかに自己文書化され、おそらくより読みやすくなります。

  4. ネットワーク経由で転送している場合(または転送していない場合でも)、不要な列は無駄になります。


7
「最も重要な実用的な理由は、ユーザーに、列が返される順序を魔法のように強制することです。」これがどのように問題であるかはわかりません。最新のDBクライアントでは、列を順序ではなく名前で読み取ります。
Josh Noe、

私はSQLをCインターフェースを介して実行する傾向があるため、「DBクライアント」の最新技術が何であるかは本当にわかりません。しかし、おそらくあなたが話している種類のクライアントは、非標準の非SQLマジックを行っていると思います。(たとえば、SQLiteでは、sqlite3_masterにクエリ*して、名前を一連の名前に変更する方法を理解します。)
pkh

さらにこれから先、列名のインデックスを使用する最新のアプリケーションで何人がコードを記述しますか?ほとんどの人は確かにある種のマッパーと古くなったデータのキャッシュ全体を使用しています。個人的には、最初にコードを記述してから、後でパフォーマンスの問題が発生するかどうかを心配します。
コリンワイズマン2017

10

誰かがテーブルに列を追加または挿入してもアプリケーションは影響を受けないため、通常は列リストの指定が最良のオプションです。


7

サーバーの場合、列名の指定は間違いなく高速です。しかし、もし

  1. パフォーマンスは大きな問題ではありません(たとえば、これは各テーブルに数百、おそらく数千(数百万ではない)の行があるWebサイトコンテンツデータベースです)。そして
  2. あなたの仕事は、複雑な1回限りのアプリケーションを作成するのではなく、共通のフレームワークを使用して、多くの小さな類似のアプリケーション(例:一般向けのコンテンツ管理Webサイト)を作成することです。そして
  3. 柔軟性は重要です(各サイトのdbスキーマの多くのカスタマイズ)。

その場合は、SELECT *を使用するほうがよいでしょう。私たちのフレームワークでは、SELECT *を頻繁に使用することで、新しいWebサイト管理コンテンツフィールドをテーブルに導入し、CMSのすべての利点(バージョニング、ワークフロー/承認など)を得ることができます。数十点ではなく、数点。

私はDBグルがこれを嫌うことを知っています-どうぞ、投票してください-私の世界では、開発者の時間が少なく、CPUサイクルが豊富であるため、節約するものと無駄にするものに応じて調整します。


1
また、ORMの使用がはるかに簡単になります。クエリ構築オブジェクトを渡してクエリを構築する場合、コードの他のどの部分でどの列が必要であったか(アクセス許可チェック、何が必要か)は必ずしも認識されていません。したがって、列を制限するには、クエリが書き込みを必要とするたびに調査する必要があります。これは無意味です、IMO。クエリが遅いことが判明した場合(logs!)、それらを改善できます。
バイトプッシャー

6

クエリがネットワーク経由で送信されない場合でも、SELECT *は悪い習慣です。

  1. 必要以上のデータを選択すると、クエリの効率が低下します。サーバーは余分なデータを読み取って転送する必要があるため、時間がかかり、システム(他の人が言及したようにネットワークだけでなく、ディスク、CPUなど)に不要な負荷がかかります。 )。さらに、サーバーはクエリを最適化できません(たとえば、クエリのカバリングインデックスを使用します)。
  2. しばらくすると、テーブル構造が変化する可能性があるため、SELECT *は異なる列のセットを返します。そのため、アプリケーションが予期しない構造のデータセットを取得し、下流のどこかで壊れることがあります。列を明示的に指定すると、既知の構造のデータセットを取得するか、データベースレベルで明確なエラー(「列が見つかりません」など)を取得することが保証されます。

もちろん、小さくてシンプルなシステムでは、これらすべてはそれほど重要ではありません。


4

パフォーマンスに関しては、特定の列を使用したSELECTの方が高速です(すべてのデータを読み取る必要はありません)。クエリが実際にすべての列を使用する場合でも、明示的なパラメーターを使用したSELECTが推奨されます。速度の違いは基本的に気づかれず、ほぼ一定の時間です。ある日、スキーマが変更されます。これは、これによる問題を防ぐための優れた保険です。


いくつかのDBを使用して行ったチェックから、各列を選択するほうがすべての列がはるかに高速であることは明らかだったので、気付かないことについては間違っています。場合によっては3倍高速でした。
shahar eldad

4

これまでに多くの正当な理由がここで答えられましたが、ここでは言及されていない別の理由があります。

列に明示的に名前を付けると、将来のメンテナンスに役立ちます。ある時点で、変更またはトラブルシューティングを行い、「その列がどこで使用されているのか」と自問することになります。

名前が明示的にリストされている場合、すべてのストアドプロシージャ、ビューなどを通じて、その列へのすべての参照を見つけるのは簡単です。DBスキーマのCREATEスクリプトをダンプし、それをテキスト検索するだけです。


3

SQL Serverは列をプルするために列を検索する必要がないため、列を明確に定義します。列を定義すると、SQLはそのステップをスキップできます。


これは次のとおりです。1)SQL Serverはいずれかの方法でテーブルスキーマを参照する必要があるため(列名を検証するため、または既知の有効な列名を検索するため)、2)すべての列が参照されている質問には関係ありません。AS ASKEDの唯一の問題は、スキーマ変更による脆弱性です。
IDisposable

それは関係なく列を検証する必要があるため、反対票を投じました。
ジョン・ギブ

3

必要な列を指定することをお勧めします。一度考えると、SQLはクエリを実行するたびに「wtfは*」であると考える必要はありません。その上、後で誰かが実際にクエリに必要のない列をテーブルに追加する可能性がありますが、その場合はすべての列を指定することでより良い結果が得られます。


1
これは真実ではありません。SQLサーバーは引き続き各列を解析して、それがカタログに存在するかどうかを確認する必要がありますが、"*"が存在することを知っています(そうです、*はすべての列に展開されます)。どちらの方法でも、DBMSがどちらか一方を実行するのは簡単です(24,000列がない場合)。したがって、どちらの方法でも同じだと思います
Matt Rogish

多くのものが欠落しているというより良い点だと思いますが、残念ながらこの答えは二次的にしか対応しません。スキーマ/テーブルの変更が発生した場合(つまり、新しい列が追加された場合)は問題が発生しません。
Sean Hanley、

1
*拡張のために列を検索することは、提供された列名を検証することと同じであるため、これは完全な洗浄です。
IDisposable

3

「select *」の問題は、本当に必要のないデータを持ち込む可能性です。実際のデータベースクエリ中に、選択した列は実際には計算に追加されません。本当に「重い」のは、クライアントへのデータ転送です。本当に必要のない列は、ネットワーク帯域幅を浪費し、クエリが返されるのを待っている時間を増やすだけです。

「select * ...」からもたらされるすべての列を使用する場合でも、それは今のところです。将来、テーブル/ビューのレイアウトを変更して列を追加すると、不要になった場合でも、それらの列を選択に含めることができます。

「select *」ステートメントが悪い別の点は、ビューの作成です。"select *"を使用してビューを作成し、後でテーブルに列を追加すると、ビューの定義と返されるデータが一致せず、ビューが再び機能するようにビューを再コンパイルする必要があります。

クエリのすべてのフィールドを手動で指定したくないので、「select *」を書くのは魅力的ですが、システムが進化し始めると、この余分な時間を費やす価値があることがわかります。 /ビューのバグの削除やアプリの最適化に多くの時間と労力を費やすのではなく、フィールドを指定するための努力。


VIEWのポイントは非常に重要です。テーブルに列を追加すると、すべての列が取得されないだけでなく(*で何を考えているかはわかりません)、実際のテーブルのレイアウトと一致しない場合もあります。
ユーロミセリ2008

3

列を明示的にリストすることはパフォーマンスに優れていますが、気が狂わないでください。

したがって、すべてのデータを使用する場合は、簡単にするためにSELECT *を試してください(多くの列があり、JOIN ...クエリを実行すると、ひどくなる場合があります)。その後-測定します。列名が明示的にリストされているクエリと比較してください。

パフォーマンスについて推測しないでください。 測定してください!

明示的なリストは、ビッグデータ(投稿や記事の本文など)を含む列があり、特定のクエリでそれを必要としない場合に最も役立ちます。次に、それを応答で返さないことにより、DBサーバーは時間、帯域幅、およびディスクスループットを節約できます。クエリ結果も小さくなるため、クエリキャッシュに適しています。


3

あなたは本当にあなたが必要なフィールドと必要な数だけを選択するべきです、すなわち

SELECT Field1, Field2 FROM SomeTable WHERE --(constraints)

データベースの外では、動的クエリがインジェクション攻撃や不正なデータのリスクを冒します。通常、これはストアドプロシージャまたはパラメータ化されたクエリを使用して回避します。また、(実際にはそれほど問題ではありませんが)動的クエリが実行されるたびに、サーバーは実行プランを生成する必要があります。


"サーバーは動的クエリが実行されるたびに実行プランを生成する必要があります"これはクエリの速度を低下させると思います。ありがとう。
Ankur

動的SQLの使用に関するパフォーマンスの問題は、おそらく非常に高い負荷のシナリオでのみ実現されます。SQLServerは、クエリプランの効率的な管理に優れています。
Matthew Abbott

2

*またはカラムを使用する場合、selectは(速度に関して)同等に効率的です。

違いはメモリではなく、速度です。複数の列を選択すると、SQL Serverは、クエリを提供するために、そのうちの1つだけを使用している場合でも、要求したすべての列のすべてのデータを含むメモリ領域を割り当てる必要があります。

パフォーマンスの点で重要なのは実行計画であり、実行計画はWHERE句とJOIN、OUTER JOINなどの数に大きく依存します...

質問にはSELECT *を使用してください。すべての列が必要な場合、パフォーマンスに違いはありません。


2

すべてのフィールドのデータを取得する必要がある場合に限り、*よりも明示的なフィールド名を使用する方が速くはありません。

クライアントソフトウェアは、返されるフィールドの順序に依存するべきではないので、それもナンセンスです。

また、存在するフィールドがまだわからないため(非常に動的なデータベース構造を考える)、*を使用してすべてのフィールドを取得する必要がある可能性があります(可能性は低いです)。

明示的なフィールド名を使用するもう1つの欠点は、フィールド名が多く、それらが長い場合、コードやクエリログの読み取りが困難になることです。

したがって、ルールは次のようになります。すべてのフィールドが必要な場合は*を使用し、サブセットのみが必要な場合は明示的に名前を付けます。


2

結果は大きすぎます。SQLエンジンからクライアントに結果を生成して送信するのに時間がかかります。

汎用プログラミング環境であるクライアント側は、行数が膨大になる可能性があるため(例:WHERE句、ORDER句など)、結果をフィルタリングして処理するようには設計されておらず、設計すべきではありません(例:数千万行)。


したがって、実際にすべての異なる列を使用する必要がある場合は問題ありません。また、データベースとアプリが同じサーバーに再度配置されている場合、それほど大きな違いはありませんか?
Ankur

@Ankur:同じサーバー上でも、データベースインターフェイスを介してデータを送信するにはコストがかかります。
kennytm

2

アプリケーションで取得する予定の各列に名前を付けることで、列が(任意の順序で)存在する限り、誰かがテーブルを変更してもアプリケーションが壊れないようにします。


1

DBサーバーのバージョンによって異なりますが、SQLの最新バージョンはどちらの方法でもプランをキャッシュできます。私はあなたのデータアクセスコードで最も保守しやすいものなら何でもいいと思います。


1

必要な列を正確に詳しく説明する方がよい理由の1つは、テーブル構造の将来の変更の可能性があるためです。

インデックスベースのアプローチを使用して手動でデータを読み取り、クエリの結果をデータ構造に入力している場合、将来、列を追加または削除するときに、何が問題だったかを解明しようとすると頭痛がするでしょう。

何が速いかについては、他の人たちの専門知識に任せます。


1

ほとんどの問題と同様に、それは達成したいことによって異なります。任意のテーブルのすべての列を許可するDBグリッドを作成する場合は、「選択*」が答えです。ただし、特定の列のみが必要で、クエリへの列の追加または削除が頻繁に行われない場合は、それらを個別に指定します。

また、サーバーから転送するデータの量によっても異なります。列の1つがメモ、グラフィック、ブロブなどとして定義されていて、その列が必要ない場合は、「選択*」を使用しない方がよいでしょう。そうしないと、大量のデータを取得できなくなります。したいとあなたのパフォーマンスが低下する可能性があります。


1

他の誰もが言ったことに加えて、選択しているすべての列がインデックスに含まれている場合、SQLから追加のデータを検索するのではなく、結果セットがインデックスからプルされます。



1

上記の誰もが言ったことに加えて:

読みやすく保守可能なコードを求めて努力しているなら、次のようなことをします:

SELECT foo、bar FROM widgets;

即座に読み取り可能であり、意図を示しています。あなたがその電話をかける場合、あなたはあなたが何を取り戻しているかを知っています。ウィジェットにfooとbarの列しかない場合、*を選択すると、返されるものを考慮し、順序が正しくマップされていることを確認する必要があります。ただし、ウィジェットの列が多くても、fooのみに関心がある場合とバーの場合、ワイルドカードを照会して返されたものの一部のみを使用すると、コードが乱雑になります。


1

また、定義によって内部結合がある場合は、結合列のデータが繰り返されるため、すべての列が必要なわけではありません。

これは、SQlサーバーで列を一覧表示するのが難しく、時間もかかるようなものではありません。オブジェクトブラウザからドラッグするだけです(列から単語をドラッグすることで、すべてを一度に実行できます)。システムに永続的なパフォーマンスヒットを与えるため(これにより、インデックスの使用が削減され、ネットワーク経由で不要なデータを送信することはコストがかかるため)、データベースが変更されると予期しない問題が発生する可能性が高くなります(列が追加されることがあります)たとえば、ユーザーに見てほしくない)開発時間を1分足らずで節約することは、近視眼的で専門外です。


1

パフォーマンスに関しては、どちらも同等であるというコメントを見てきました。しかし、ユーザビリティの側面にはいくつかの+と-があります

クエリで(select *)を使用し、誰かがテーブルを変更し、前のクエリに必要のない新しいフィールドを追加した場合、不要なオーバーヘッドになります。新しく追加されたフィールドがblobまたは画像フィールドの場合はどうなりますか??? その場合、クエリの応答時間は本当に遅くなります。

一方、(select col1、col2、..)を使用し、テーブルが変更されて新しいフィールドが追加された場合、およびそれらのフィールドが結果セットで必要な場合は、常にテーブル変更後に選択クエリを編集する必要があります。

ただし、クエリでは常にselect col1、col2、...を使用し、後でテーブルが変更された場合はクエリを変更することをお勧めします...


0

毎回SELECTする列を絶対的に定義します。しない理由はなく、パフォーマンスの向上はそれだけの価値があります。

彼らは「選択*」するオプションを与えてはならない


0

すべての列が必要な場合は、SELECT *を使用するだけですが、結果が消費されるときに、インデックスではなく名前で列にアクセスするため、順序が変わる可能性があることに注意してください。

*がリストを取得する方法についてのコメントは無視します。名前付きの列が解析および検証される可能性は、処理時間と同じかそれ以上です。時期尚早に最適化しないでください;-)


0

実行効率に関しては、大きな違いはありません。しかし、プログラマーの効率のために、フィールドの名前を書きます。

  • 番号でインデックスを作成する必要がある場合、またはドライバーがblob値で面白い動作をする場合、および明確な順序が必要な場合は、順序を知っています。
  • フィールドを追加する必要がある場合は、必要なフィールドのみを読み取ります。
  • レコードセット/行の空の値ではなく、フィールドのスペルミスまたは名前の変更を行うと、SQLエラーが発生します
  • あなたは何が起こっているのかをよりよく読むことができます。

0

ねえ、実用的です。プロトタイピング時にはselect *を使用し、実装およびデプロイ時には特定の列を選択します。実行計画の観点から見ると、どちらも最新のシステムでは比較的同じです。ただし、特定の列を選択すると、ディスクから取得してメモリに格納し、ネットワーク経由で送信する必要があるデータの量が制限されます。

最終的には、特定の列を選択するのが最善の計画です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.