web-dev-qa-db-ja.com

テーブルの列の順序を気にする理由はありますか?

MySQLでFIRSTとAFTERを使用して列の順序を変更できることは知っていますが、なぜ煩わしいのでしょうか。優れたクエリはデータを挿入するときに列に明示的に名前を付けるので、列がテーブルのどの順序にある​​かを気にする理由は本当にありますか?

78
lynn

列の順序は、Sql Server、Oracle、MySQLにまたがる、私が調整したいくつかのデータベースに大きなパフォーマンスの影響を与えました。この投稿には 優れた経験則 があります。

  • 最初に主キー列
  • 次に外部キー列。
  • 次によく検索される列
  • 後で頻繁に更新される列
  • NULL可能列は最後です。
  • 使用頻度の高いnull可能列の後に使用頻度が最も低いnull可能列

パフォーマンスの違いの例は、インデックスルックアップです。データベースエンジンは、インデックスのいくつかの条件に基づいて行を検索し、行アドレスを取得します。ここで、SomeValueを探していて、それがこの表にあるとします。

 SomeId int,
 SomeString varchar(100),
 SomeValue int

SomeStringの長さが不明なため、エンジンはSomeValueの開始位置を推測する必要があります。ただし、順序を次のように変更した場合:

 SomeId int,
 SomeValue int,
 SomeString varchar(100)

これでエンジンは、SomeValueが行の先頭の4バイト後にあることを認識します。したがって、列の順序はパフォーマンスに大きな影響を与える可能性があります。

編集:SQL Server 2005は、行の先頭に固定長フィールドを格納します。また、各行にはvarcharの開始への参照があります。これは、上記の効果を完全に打ち消します。したがって、最近のデータベースでは、列の順序による影響はなくなりました。

89
Andomar

更新:

MySQLでは、これを行う理由があるかもしれません。

変数データ型(VARCHARなど)は可変長でInnoDBに格納されるため、データベースエンジンは各行の以前のすべての列をトラバースして、指定された列のオフセットを見つける必要があります。

20列では、影響が17%になる可能性があります。

詳細については、私のブログのこのエントリを参照してください。

Oracleでは、後続のNULL列はスペースを消費しないため、常にテーブルの最後に配置する必要があります。

また、OracleSQL Serverでは、行が大きい場合、ROW CHAININGが発生することがあります。

ROW CHANINGは、1つのブロックに収まらない行を分割し、リンクリストで接続された複数のブロックにまたがっています。

最初のブロックに収まらない末尾の列を読み取るには、リンクされたリストをたどる必要があり、追加のI/O操作が発生します。

OracleROW CHAININGの図については、 このページ を参照してください:

そのため、頻繁に使用する列と使用頻度の低い列、またはNULLになりがちな列は、テーブルの最後に配置する必要があります。

重要な注意:

この回答が気に入って投票したい場合は、 @Andomarの回答 にも投票してください。

彼は同じことを答えたが、理由もなく反対票を投じられたようだ。

39
Quassnoi

前のジョブでのOracleトレーニング中に、DBAは、null可能でない列の前にすべてのnull可能ではない列を配置することが有利だと提案しました... TBH理由の詳細は覚えていません。またはおそらくそれは、更新される可能性が高いものだけでしたか?(拡張された場合、行を移動する必要がなくなるかもしれません)

一般的に、それは違いを生むべきではありません。あなたが言うように、クエリは常に「select *」からの順序に依存するのではなく、列自体を指定する必要があります。それらを変更できるDBについては知りません。

6
araqnid

いいえ、SQLデータベーステーブルの列の順序は、表示/印刷の目的を除いて、まったく関係ありません。列を並べ替える意味はありません-ほとんどのシステムは、それを行う方法さえ提供していません(古いテーブルを削除して、新しい列の順序で再作成することを除く)。

マーク

編集:リレーショナルデータベースのWikipediaエントリから、関連する部分を以下に示します。これは、列の順序が決して気にする必要がないことを明確に示しています。

リレーションは、nタプルのセットとして定義されます。数学とリレーショナルデータベースモデルの両方で、セットはnordered項目のコレクションですが、一部のDBMSはデータに順序を課しています。数学では、タプルには順序があり、複製が可能です。 E.F. Coddは最初、この数学的定義を使用してタプルを定義しました。その後、それはE.F. Coddの優れた洞察の1つであり、順序付けの代わりに属性名を使用すると、関係に基づくコンピューター言語では(一般的に)はるかに便利になります。この洞察は今日でも使用されています。

5
marc_s

不適切に作成されたアプリケーションの中には、列名ではなく列の順序/インデックスに依存しているものがあります。彼らはそうではありませんが、それは起こります。列の順序を変更すると、このようなアプリケーションが機能しなくなります。

5
Craig Walker

入力する必要がある場合の出力の読みやすさ:

select * from <table>

データベース管理ソフトウェアで?

それは非常に偽の理由ですが、現時点では他に何も考えられません。

4
ChrisF

私が考えることができる唯一の理由は、デバッグと消防のためです。 「名前」列がリストの約10番目にあるテーブルがあります。 id from(1,2,3)のテーブルから*をすばやく選択し、名前を確認するためにスクロールする必要がある場合、これは面倒です。

しかし、それはそれについてです。

2
Chris Simpson

明らかなパフォーマンスチューニングを超えて、列を並べ替えると(以前は機能していた)SQLスクリプトが失敗するというコーナーケースに遭遇しました。

ドキュメントから「明示的に指定されていない限り、TIMESTAMP列とDATETIME列には自動プロパティはありませんが、この例外があります。デフォルトでは、最初のTIMESTAMP列にはDEFAULT CURRENT_TIMESTAMPとON UPDATE CURRENT_TIMESTAMPの両方が明示的に指定されていない場合」 https:/ /dev.mysql.com/doc/refman/5.6/en/timestamp-initialization.html

そのため、コマンドALTER TABLE table_name MODIFY field_name timestamp(6) NOT NULL;は、そのフィールドがテーブルの最初のタイムスタンプ(または日時)である場合は機能しますが、それ以外の場合は機能しません。

もちろん、alterコマンドを修正してデフォルト値を含めることができますが、列の並べ替えが原因で機能したクエリが機能しなくなったため、頭が痛くなりました。

1
slacker525600

よくあることですが、最大の要因はシステムで作業しなければならない次の人です。最初に主キー列、次に外部キー列、次にシステムの重要度/重要度の降順で残りの列を配置しようとします。

1
James L

UNIONを頻繁に使用する場合、列の順序に慣例があれば、列のマッチングが容易になります。

1
Allain Lalonde

カラムの順序について心配する必要があるのは、ソフトウェアがその順序に特に依存している場合だけです。通常、これは、開発者が怠惰になり、select *し、結果では名前ではなくインデックスで列を参照しました。

0
Soviut

一般に、SQL ServerでManagement Studioを使用して列の順序を変更すると、新しい構造の一時テーブルが作成され、古いテーブルからその構造にデータが移動され、古いテーブルが削除され、新しいテーブルの名前が変更されます。ご想像のとおり、大きなテーブルがある場合、これはパフォーマンスにとって非常に悪い選択です。私のSQLが同じことを行うかどうかはわかりませんが、多くの人が列の並べ替えを避けている理由の1つです。 select *は本番システムでは使用しないでください。最後に列を追加しても、適切に設計されたシステムでは問題になりません。テーブルの列の順序は、一般的なものではありません。

0
HLGEM

前述のように、潜在的なパフォーマンスの問題が多数あります。クエリでこれらの列を参照しなかった場合に、最後に非常に大きな列を配置するとパフォーマンスが向上するデータベースで作業しました。明らかに、レコードが複数のディスクブロックにまたがっている場合、データベースエンジンは、必要なすべての列を取得すると、ブロックの読み取りを停止する可能性があります。

もちろん、パフォーマンスへの影響は、使用している製造元だけでなく、バ​​ージョンにも大きく依存します。数か月前、私はPostgresが "like"比較にインデックスを使用できないことに気付きました。つまり、「 'M%'のようないくつかの列」を記述した場合、最初のNを見つけてMにスキップして終了するのは賢くありませんでした。「between」を使用するように一連のクエリを変更する予定でした。次に、Postgresの新しいバージョンを取得し、それは同様のものをインテリジェントに処理しました。クエリを変更することに慣れなかったことをうれしく思います。明らかにここでは直接関係ありませんが、私の考えは、効率を考慮して行うことは次のバージョンでは廃止される可能性があるということです。

画面を作成するためにデータベーススキーマを読み取る汎用コードを日常的に作成しているため、ほとんどの場合、列の順序は非常に重要です。同様に、「レコードの編集」画面は、ほとんどの場合、スキーマを読み取ってフィールドのリストを取得し、それらを順番に表示することによって構築されます。列の順序を変更しても、プログラムは機能しますが、ユーザーにとって表示がおかしいかもしれません。同様に、都市/住所/郵便番号/名前/州ではなく、名前/住所/都市/州/郵便番号が表示されることを期待しています。もちろん、列の表示順序をコードや制御ファイルなどに入れることはできますが、列を追加または削除するたびに、制御ファイルを更新する必要があることを覚えておく必要があります。一度言うのが好きです。また、編集画面が純粋にスキーマから構築されている場合、新しいテーブルを追加することは、そのための編集画面を作成するためのゼロ行のコードを書くことを意味する場合があり、これはかなりクールです。 (まあ、大丈夫、実際には通常、一般的な編集プログラムを呼び出すためにメニューにエントリを追加する必要があります。また、一般的な「更新するレコードを選択する」は、例外が多すぎて実用的ではないため、一般的にあきらめました。)

0
Jay