24

「*」を使用してビューを作成するのはなぜ悪いのですか?

複雑な結合があり、すべてのフィールドがどこかで使用される可能性があるとします。

次に、必要なフィールドを選択するだけです。

SELECT field1, field2 FROM aview WHERE ...

ビュー「aview」はSELECT table1.*, table2.* ... FROM table1 INNER JOIN table2 ...

table1 と table2 で 2 つのフィールドが同じ名前の場合、問題が発生します。

ビューで「*」を使用するのが悪い理由はこれだけですか?

「*」を使用すると、情報が存在するため、別のコンテキストでビューを使用できます。

何が欠けていますか?

よろしく

4

14 に答える 14

37

ソフトウェアには「ただ悪い」ものはあまりないと思いますが、悪い意味で悪用されているものはたくさんあります:-)

あなたが与えた例は、 * があなたが期待したものを与えないかもしれない理由であり、他にもあると思います. たとえば、基になるテーブルが変更された場合、おそらく列が追加または削除された場合、* を使用するビューは引き続き有効ですが、それを使用するアプリケーションが破損する可能性があります。ビューが列に明示的に名前を付けていた場合、スキーマを変更するときに誰かが問題を発見する可能性が高くなります。

一方、実際には、ビューが基になるテーブルへのすべての変更を素直に受け入れるようにしたい場合があります。その場合、* はまさにあなたが望むものです。

更新: OP が特定のデータベース ベンダーを念頭に置いていたかどうかはわかりませんが、最後の発言がすべてのタイプに当てはまるわけではないことは明らかです。これを指摘してくれた user12861 と Jonny Leeds に感謝します。回答を編集するのに 6 年以上かかりました。

于 2008-11-04T16:56:57.720 に答える
19

ここでのコメントの多くは非常に優れており、基になるテーブルが変更された場合にエラーが発生したり異なる結果が発生したりするなど、クエリでワイルドカードを使用する際の 1 つの一般的な問題を参照していますが、カバーされていない別の問題は最適化です。テーブルのすべての列を取得するクエリは、実際に必要な列のみを取得するクエリほど効率的ではない傾向があります。確かに、すべての列が必要な場合があり、特に大きなテーブルでは、それらすべてを参照する必要があるのは主要な PIA ですが、サブセットのみが必要な場合は、必要以上の列でクエリを停止させる必要があります。

于 2008-11-04T17:05:51.073 に答える
17

*" " がビューだけでなくクエリでも危険であるもう 1 つの理由は、列が名前を変更したり、基になるテーブルの位置を変更したりする可能性があることです。ワイルドカードを使用すると、ビューを変更する必要なく、そのような変更に簡単に対応できます。ただし、アプリケーションが結果セット内の位置で列を参照する場合、または列名でキー付けされた結果セットを返す動的言語を使用する場合、デバッグが困難な問題が発生する可能性があります。

私は常にワイルドカードの使用を避けています。そうすれば、列の名前が変更された場合、ビューまたはクエリですぐにエラーが発生し、どこを修正すればよいかがわかります。基になるテーブルで列の位置が変更された場合、ビューまたはクエリで列の順序を指定すると、これが補正されます。

于 2008-11-04T17:01:30.287 に答える
13

これらの他の回答にはすべて良い点がありますが、少なくとも SQL サーバーではいくつかの間違った点もあります。これを試して:

create table temp (i int, j int)
go
create view vtemp as select * from temp
go
insert temp select 1, 1
go
alter table temp add k int
go
insert temp select 1, 1, 1
go
select * from vtemp

SQL Server は、追加されたときに "新しい" 列について学習しません。あなたが望むものによって、これは良いことにも悪いことにもなり得ますが、どちらにしても、それに依存することはおそらく良くありません. したがって、それを避けることは良い考えのようです。

私にとって、この奇妙な動作は、ビューで select * を避けるべき最も説得力のある理由です。

コメントは、MySQL には同様の動作があり、Oracle にはないことを教えてくれました (テーブルへの変更について学習します)。私にとってのこの矛盾は、ビューで select * を使用しないよりも多くの理由です。

于 2008-11-04T20:30:16.357 に答える
11

生産に「*」を使用するのは悪いことです。これは 1 回限りのクエリには最適ですが、実稼働コードでは常に可能な限り明示的にする必要があります。

特にビューの場合、基になるテーブルに列が追加または削除されている場合、ビューは再コンパイルされるまで間違っているか壊れています。

于 2008-11-04T16:57:40.870 に答える
4

ビュー内で使用SELECT *する場合、ビュー外で列を使用しない場合、パフォーマンスのオーバーヘッドはそれほど発生しません。オプティマイザーが列を最適化します。SELECT * FROM TheViewネットワーク接続を介してより多くの列をプルするときと同じように、おそらく帯域幅を浪費する可能性があります。

実際、データウェアハウス内の多数の巨大なテーブルのほぼすべての列をリンクするビューでは、ビューの外部から要求される列が比較的少ない場合でも、パフォーマンスの問題はまったく発生していません。オプティマイザーはそれをうまく処理し、外部フィルター基準をビューに非常にうまくプッシュすることができます。

ただし、上記のすべての理由から、を使用することはめったにありませんSELECT *

いくつかのCTEが相互に構築され、派生列から派生列から派生列を効果的に構築するビジネスプロセスがいくつかあります(これは、ビジネスがこれらの計算を合理化および簡素化するときに、いつかリファクタリングされることを願っています)。 、毎回すべての列をドロップスルーする必要があります。使用しますSELECT *SELECT *、ベースレイヤーでは使用されず、最初のCTEと最後のCTEの間でのみ使用されます。

于 2008-11-04T17:42:23.713 に答える
4

実際、SQL Server の状況は、@ user12861 の回答が示唆するよりもさらに悪いものです。SELECT *複数のテーブルに対して使用する場合、クエリの早い段階で参照されるテーブルに列を追加すると、実際にはビューが偽装して新しい列の値を返すことになります。古い列の。以下の例を参照してください。

-- create two tables
CREATE TABLE temp1 (ColumnA INT, ColumnB DATE, ColumnC DECIMAL(2,1))
CREATE TABLE temp2 (ColumnX INT, ColumnY DATE, ColumnZ DECIMAL(2,1))
GO


-- populate with dummy data
INSERT INTO temp1 (ColumnA, ColumnB, ColumnC) VALUES (1, '1/1/1900', 0.5)
INSERT INTO temp2 (ColumnX, ColumnY, ColumnZ) VALUES (1, '1/1/1900', 0.5)
GO


-- create a view with a pair of SELECT * statements
CREATE VIEW vwtemp AS 
SELECT *
FROM temp1 INNER JOIN temp2 ON 1=1
GO


-- SELECT showing the columns properly assigned
SELECT * FROM vwTemp 
GO


-- add a few columns to the first table referenced in the SELECT 
ALTER TABLE temp1 ADD ColumnD varchar(1)
ALTER TABLE temp1 ADD ColumnE varchar(1)
ALTER TABLE temp1 ADD ColumnF varchar(1)
GO


-- populate those columns with dummy data
UPDATE temp1 SET ColumnD = 'D', ColumnE = 'E', ColumnF = 'F'
GO


-- notice that the original columns have the wrong data in them now, causing any datatype-specific queries (e.g., arithmetic, dateadd, etc.) to fail
SELECT *
FROM vwtemp
GO

-- clean up
DROP VIEW vwTemp
DROP TABLE temp2
DROP TABLE temp1
于 2015-10-16T18:51:11.243 に答える
3

これは、常にすべての変数が必要なわけではなく、具体的に必要なものについて考えていることを確認するためでもあります。

たとえば、サイトでユーザーのリストを作成するときに、データベースからすべてのハッシュ化されたパスワードを取得しても意味がないため、select * は非生産的です。

于 2008-11-04T16:55:42.373 に答える
3

SQL クエリは基本的に、あるコンテキストで使用するためにプログラマーによって設計された機能単位です。長期的な安定性とサポート可能性 (おそらくあなた以外の誰かによるもの) のためには、機能単位のすべてが目的のためにそこにある必要があり、それがなぜそこにあるのか (特にデータのすべての要素) が合理的に明白 (または文書化) されている必要があります。

2年後にあなたのクエリを変更する必要がある、または変更したい場合、私はそれをいじることができると確信する前に、それをかなり徹底的に理解することを期待します. つまり、すべての列が呼び出される理由を理解する必要があります。(これは、クエリを複数のコンテキストで再利用しようとしている場合に、より明確に当てはまります。これは、同様の理由で、一般的に問題となります。)出力に列が表示された場合、何らかの目的に関連付けることができませんでした。 、私はそれが何をしたのか、なぜ、そしてそれを変更した結果がどうなるかを理解していなかったと確信しています.

于 2008-11-06T03:41:32.053 に答える
3

むかしむかし、別のデータベース(同じサーバー上)のテーブルに対してビューを作成しました

Select * From dbname..tablename

そんなある日、対象のテーブルに列が追加されました。ビューは、再デプロイされるまで、まったく正しくない結果を返し始めました。


完全に間違っています: 行がありません。

これはSql Server 2000上にありました。

これは、*.

于 2008-11-04T16:57:20.887 に答える
2

使う言語にもよると思います。言語または DB ドライバーが結果の dict (Python、Perl など) または連想配列 (PHP) を返す場合は、select * を使用することを好みます。配列内のインデックスではなく名前で列を参照している場合、コードが理解しやすくなります。

于 2008-11-04T18:32:12.490 に答える
2

誰も言及していないようですが、SQL Server 内では、schemabinding属性を使用してビューを設定することもできます。

これにより、ビューの定義に影響を与えるベース テーブルの変更 (削除を含む) が防止されます。

これは、状況によっては役立つ場合があります。あなたの質問に正確に答えていないことは承知していますが、それでも強調したいと思います。

于 2008-11-05T23:44:03.203 に答える
2

一般に、* を使用することはお勧めできません。一部のコード認証エンジンは、これを警告としてマークし、必要な列のみを明示的に参照するようにアドバイスします。* を使用すると、すべてではなく一部の列のみが必要になる場合があるため、パフォーマンスが低下する可能性があります。しかし一方で、* の使用が理想的な場合もあります。あなたが提供した例を使用して、このビュー(aview)に対して、これらのテーブルのすべての列が常に必要になると想像してください。将来、列が追加されたときに、ビューを変更する必要はありません。これは、扱っているケースに応じて、良い場合も悪い場合もあります。

于 2008-11-04T17:19:04.870 に答える
1

また、select *を使用して結合している場合は、結合フィールドのデータが繰り返されるため、必要以上のデータが自動的に返されることを意味します。これはデータベースとネットワークリソースの浪費です。

他のビューを呼び出すビューを使用するのに十分な経験がない場合、select *を使用すると、パフォーマンスがさらに低下する可能性があります(これは、それ自体でパフォーマンスに悪影響を与える手法であり、不要な複数の列を呼び出すと、パフォーマンスが大幅に低下します)。

于 2010-12-07T15:41:28.667 に答える