テーブルの列の順序について心配する理由はありますか?


84

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

回答:


94

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

  • 最初に主キー列
  • 次の外部キー列。
  • 次によく検索される列
  • 後で頻繁に更新される列
  • null許容列は最後です。
  • より頻繁に使用されるNULL可能列の後に、最も使用されていないNULL可能列

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

 SomeId int,
 SomeString varchar(100),
 SomeValue int

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

 SomeId int,
 SomeValue int,
 SomeString varchar(100)

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

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


4
@TopBanana:varcharではなく、それが通常のchar列との違いです。
Allain Lalonde

1
表の列の順序に違いはないと思います。作成する可能性のあるインデックスに間違いなく違いがあります。
marc_s 2009年

4
@TopBanana:Oracleを知っているかどうかはわかりませんが、VARCHAR2(100)用に100バイトを予約していません
Quassnoi 2009年

1
@Quassnoi:最大の影響は、SQL Server、null許容のvarchar()列が多数あるテーブルにありました。
Andomar 2009年

7
この回答のURLは機能しなくなりました。別のURLはありますか?
scunliffe 2013

41

更新:

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

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

影響は、カラムで最大17%になる可能性があり20ます。

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

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

また、内OracleとでSQL Server、大行の場合には、AROW CHAINING発生する可能性があります。

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

最初のブロックに収まらなかった後続の列を読み取るには、リンクリストをトラバースする必要があり、追加のI/O操作が発生します。

参照このページをの説明のためROW CHAININGにありますOracle

そのため、頻繁に使用する列をテーブルの先頭に配置し、頻繁に使用しない列、または頻繁に使用する列をNULLテーブルの末尾に配置する必要があります。

重要な注意点:

もしこの答えのような、それのために投票したい場合は、またのために投票してください@Andomarの答え

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


1
つまり、これは遅いと言っています。tinyTableの内部結合tblBIGからtinyTable.id、tblBIG.firstColumn、tblBIG.lastColumnを選択します。tinyTable.id= tblBIG.fkID tblBIGレコードが8KBを超える場合(この場合、行の連鎖が発生します) )および結合は同期されます...しかし、これは高速です:tinyTableからtinyTable.id、tblBIG.firstColumnを選択します:tinyTable.id = tblBIG.fkIDの内部結合tblBIG他のブロックでは列を使用しないため、リンクリストをトラバースする必要がありますこれは正しいですか?
jfrobishow 2009年

1
私は6%しか得られません、そしてそれは他のどの列に対してcol1のためです。
リックジェームス

6

前の仕事でのOracleトレーニング中に、DBAは、null許容でない列をすべてnull許容列の前に配置することが有利であると提案しました... TBH理由の詳細は覚えていませんが。それとも、更新される可能性が高いのは最後に行くべきだったのでしょうか?(行が拡張された場合、行を移動する必要があるのを延期するかもしれません)

一般的に、それは何の違いももたらさないはずです。あなたが言うように、クエリは「select *」からの順序に依存するのではなく、常に列自体を指定する必要があります。それらを変更できるDBを私は知りません...まあ、あなたがそれを言うまで、MySQLがそれを許可したことを知りませんでした。


4
彼は正しかった。Oracleは末尾のNULL列をディスクに書き込まず、一部のバイトを節約します。dba-oracle.com/oracle_tips_ault_nulls_values.htm
Andomar

絶対に、それはディスク上のサイズに大きな違いをもたらす可能性があります
Alex

それはあなたが意図したリンクですか?これは、列の順序ではなく、インデックス内のnullの非インデックス化に関連しています。
araqnid 2009年

リンクが間違っており、オリジナルが見つかりません。あなたはそれをグーグルで検索
Andomar

5

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


3
テーブルの列の順序にコードを依存させるアプリケーション開発者は、アプリケーションを壊す必要があります。しかし、アプリケーションのユーザーは停止に値しません。
spencer7593 2009年

4

次のように入力する必要がある場合の出力の読みやすさ。

select * from <table>

あなたのデータベース管理ソフトウェアで?

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


4

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

マーク

編集:リレーショナルデータベースのウィキペディアのエントリから、列の順序が問題になることはないことを明確に示している関連部分があります。

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


1
列の違いが自分の目で大きな影響を与えるのを見たので、これが正しい答えだとは信じられません。投票が最優先ですが。うーん。
Andomar 2009年

それはどのSQL環境にありますか?
marc_s 2009年

1
私が見た中で最大の影響は、外部キーを前方に移動すると一部のクエリが2〜3倍高速化されたSQL Server2000でした。これらのクエリには、外部キーを条件とする大きなテーブルスキャン(100万行以上)がありました。
Andomar 2009年

5
RDBMSは、パフォーマンスを気にしない限り、テーブルの順序に依存しません。実装が異なれば、列の順序に対するパフォーマンスのペナルティも異なります。それは巨大かもしれないし、小さいかもしれません、それは実装に依存します。タプルは理論的であり、RDBMSは実用的です。
エステバンKüber

3
-1。私が使用したすべてのリレーショナルデータベースには、あるレベルでの列の順序があります。テーブルから*を選択した場合、列がランダムな順序で戻されることはあまりありません。現在、オンディスクとディスプレイは別の議論です。そして、データベースの実際の実装についての仮定を裏付けるために数学理論を引用することは、まったくナンセンスです。
DougW 2013

2

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

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


1

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


通常、最後の列が「作成」されることから始めます(行が挿入されるときのタイムスタンプ)。もちろん、古いテーブルでは、その後に複数の列を追加できます...そして、複合主キーが代理キーに変更されたため、主キーが数列上にあるテーブルがときどきあります。
araqnid 2009年

1

UNIONを頻繁に使用する場合は、順序に関する規則があると、列の照合が簡単になります。


データベースを正規化する必要があるようです。:)
James L

ねえ!それを取り戻してください、私は私のデータベースを言いませんでした。:)
Allain Lalonde

UNIONを使用するための合法的な理由があります;)を参照してください postgresql.org/docs/current/static/ddl-partitioning.htmlstackoverflow.com/questions/863867/...
エステバンKüber

2つのテーブルの列の順序が異なるUNIONを実行できますか?
Monica Heddneck 2016

はい、テーブルをクエリするときに列を明示的に指定する必要があります。テーブルA [a、b] B [b、a]の場合、(SELECT aa、ab FROM A)UNION(SELECT ba、bb FROM B)が(SELECT * FROM A)UNION(SELECT * FROM B)の内側にあることを意味します。
Allain Lalonde

1

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

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

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


1

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

ドキュメントから「TIMESTAMP列とDATETIME列には、明示的に指定されていない限り、自動プロパティはありません。ただし、この例外があります。デフォルトでは、最初のTIMESTAMP列には、明示的に指定されていない場合、DEFAULTCURRENT_TIMESTAMPとONUPDATECURRENT_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コマンドを修正してデフォルト値を含めることはできますが、列の並べ替えが原因で機能したクエリが機能しなくなったため、頭が痛くなりました。


0

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


0

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


0

2002年、Bill Thorsteinsonは、列を並べ替えることによってMySQLクエリを最適化するための提案をHewlettPackardフォーラムに投稿しました。それ以来、彼の投稿は文字通りコピーされ、インターネット上に少なくとも100回貼り付けられており、多くの場合、引用されていません。彼を正確に引用するには...

一般的な経験則:

  • 最初に主キー列。
  • 次の外部キー列。
  • 次によく検索される列。
  • 後で頻繁に更新される列。
  • null許容列は最後です。
  • 使用頻度の低いNULL可能列の後に、使用頻度の低いNULL可能列。
  • 他の列がほとんどない独自のテーブルのブロブ。

出典:HPフォーラム。

しかし、その投稿は2002年にすべて行われたものです。 このアドバイスは、MySQL 5.1がリリースされる6年以上前の、MySQLバージョン3.23に対するものでした。 また、参考文献や引用はありません。それで、ビルは正しかったですか?そして、ストレージエンジンはこのレベルでどの程度正確に機能しますか?

  1. はい、ビルは正しかった。
  2. それはすべて、連鎖した行とメモリブロックの問題に帰着します。

オラクル認定の専門家あるマーティン・ザーンを、オラクルの行の連鎖と移行の秘密に関する記事で引用する...

連鎖した行は、私たちに異なる影響を与えます。ここでは、必要なデータによって異なります。2つのブロックにまたがる2つの列を持つ行がある場合、クエリは次のようになります。

SELECT column1 FROM table

column1がブロック1にある場合、「テーブルフェッチの継続行」は発生しません。実際にはcolumn2を取得する必要はなく、チェーンされた行を完全に追跡することはありません。一方、私たちが求める場合:

SELECT column2 FROM table

列2は行チェーンのためにブロック2にあり、実際には「テーブルフェッチの継続行」が表示されます。

記事の残りの部分はかなり良い読み物です!しかし、ここでは、当面の質問に直接関連する部分のみを引用しています。

18年以上後、私はそれを言わなければなりません:ありがとう、ビル!

MySQL行のデータブロックへのマッピング

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