FIRST と AFTER を使用して MySQL の列の順序を ALTER できることは知っていますが、なぜそんなことをしたいのでしょうか? 優れたクエリでは、データを挿入するときに列に明示的に名前を付けるので、テーブル内での列の順序を気にする理由は本当にありますか?
14 に答える
列の順序は、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 の先頭への参照があります。これは、上に挙げた効果を完全に無効にします。そのため、最近のデータベースでは、列の順序は影響を受けなくなりました。
アップデート:
ではMySQL
、これを行う理由がある場合があります。
可変データ型 ( などVARCHAR
) は可変長で に格納されるInnoDB
ため、データベース エンジンは各行の前のすべての列を走査して、指定された列のオフセットを見つける必要があります。
列の場合、影響は17%にもなる可能性があり20
ます。
詳細については、私のブログのこのエントリを参照してください。
ではOracle
、末尾NULL
の列はスペースを消費しないため、常にテーブルの最後に配置する必要があります。
Oracle
、においてもSQL Server
、行数が多い場合、ROW CHAINING
が発生する場合があります。
ROW CHANING
1 つのブロックに収まらない行を分割し、リンクされたリストで接続された複数のブロックにまたがっています。
最初のブロックに収まらなかった末尾の列を読み取るには、リンクされたリストをトラバースする必要があり、余分なI/O
操作が必要になります。
の説明については、このページを参照してください。ROW CHAINING
Oracle
そのため、よく使う列は表の先頭に、あまり使わない列やそうなりがちな列NULL
は表の最後に配置する必要があります。
重要な注意点:
@Andomar
この回答が気に入って投票したい場合は、の回答にも投票してください。
彼は同じことを答えましたが、理由もなく反対票を投じられたようです。
前職での Oracle のトレーニング中に、DBA は、null 値を許容できない列をすべて null 値を許容する列の前に配置することが有利であると提案しましたが、理由の詳細は覚えていません。それとも、更新される可能性が高いものだけが最後に行くべきだったのでしょうか? (おそらく、行が拡張された場合に行を移動する必要があるのを延期します)
一般に、違いはありません。あなたが言うように、クエリは「select *」からの順序に依存するのではなく、常に列自体を指定する必要があります。それらを変更できるDBを知りません...まあ、あなたが言及するまでMySQLがそれを許可していることを知りませんでした。
次のように入力する必要がある場合の出力の読みやすさ:
select * from <table>
データベース管理ソフトウェアで?
それは非常に偽りの理由ですが、現時点では他に何も考えられません。
一部の不適切に作成されたアプリケーションは、列名ではなく列の順序/インデックスに依存している可能性があります。そうあるべきではありませんが、実際に起こります。列の順序を変更すると、そのようなアプリケーションが壊れます。
明らかなパフォーマンス チューニングを超えて、列の並べ替えが原因で (以前は機能していた) 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 コマンドを修正してデフォルト値を含めることもできますが、機能していたクエリが列の並べ替えによって機能しなくなったという事実に頭が痛くなりました。
いいえ、SQL データベース テーブルの列の順序はまったく関係ありません - 表示/印刷目的を除いて。列を並べ替えても意味がありません。ほとんどのシステムでは、それを行う方法さえ提供されていません (古いテーブルを削除して、新しい列の順序で再作成する以外は)。
マルク
編集:リレーショナルデータベースに関するウィキペディアのエントリから、列の順序が決して重要ではないことを明確に示している関連部分を次に示します。
リレーションは n タプルのセットとして定義されます。数学とリレーショナル データベース モデルの両方で、セットは項目の順序付けられていないコレクションですが、一部の DBMS ではデータに順序が課されます。数学では、タプルには順序があり、重複が可能です。EF Codd は元々、この数学的定義を使用してタプルを定義しました。後で、関係に基づくコンピューター言語では、順序付けの代わりに属性名を使用する方が (一般的に) はるかに便利であるということは、EF Codd の優れた洞察の 1 つでした。この洞察は現在でも使用されています。
よくあることですが、最大の要因は、次にシステムに取り組まなければならない人です。最初に主キー列、2 番目に外部キー列、次に残りの列をシステムにとっての重要性/重要度の降順で配置しようとしています。
私が考えることができる唯一の理由は、デバッグと消火のためです。「名前」列がリストの約 10 番目に表示されるテーブルがあります。クイック select * from table where id in (1,2,3) を実行し、スクロールして名前を確認するのは面倒です。
しかし、それはそれについてです。
前述のように、潜在的なパフォーマンスの問題が多数あります。クエリでそれらの列を参照しない場合、最後に非常に大きな列を配置するとパフォーマンスが向上するデータベースで作業したことがあります。どうやら、レコードが複数のディスク ブロックにまたがる場合、データベース エンジンは、必要なすべての列を取得すると、ブロックの読み取りを停止する可能性があります。
もちろん、パフォーマンスへの影響は、使用しているメーカーだけでなく、バージョンにも大きく依存します。数か月前、私たちの Postgres が「類似」比較にインデックスを使用できないことに気付きました。つまり、"somecolumn like 'M%'" と書いた場合、M までスキップして最初の N を見つけた時点で終了するほど賢くありませんでした。その後、Postgres の新しいバージョンを入手し、同様のものをインテリジェントに処理しました。クエリを変更することはできませんでした。明らかにここでは直接関係ありませんが、私が言いたいのは、効率を考慮して行うことは、次のバージョンでは時代遅れになる可能性があるということです。
私はデータベース スキーマを読み取って画面を作成する一般的なコードを日常的に書いているため、列の順序はほとんどの場合、私にとって非常に重要です。同様に、私の「レコードの編集」画面は、ほとんどの場合、スキーマを読み取ってフィールドのリストを取得し、それらを順番に表示することによって構築されています。列の順序を変更してもプログラムは動作しますが、ユーザーにとって表示が奇妙になる可能性があります。同様に、都市/住所/郵便番号/名前/州ではなく、名前/住所/都市/州/郵便番号が表示されることを期待しています。確かに、列の表示順序をコードや制御ファイルなどに入れることはできますが、列を追加または削除するたびに、制御ファイルを更新することを覚えておく必要があります。私は物事を一度言うのが好きです。また、純粋にスキーマから編集画面を構築すると、新しいテーブルを追加するということは、そのテーブルの編集画面を作成するためのコードをまったく書かないことを意味します。これは非常に優れています。(ええと、実際には、通常、一般的な編集プログラムを呼び出すためにメニューにエントリを追加する必要があります。一般的には、一般的な「更新するレコードを選択する」ことをあきらめました。実用化するには例外が多すぎるためです。 .)
UNION を頻繁に使用する場合は、列の順序に関する規則があると、列の一致が容易になります。
列の順序について心配する必要があるのは、ソフトウェアが特にその順序に依存している場合だけです。通常、これは、開発者が怠惰になりselect *
、結果で名前ではなくインデックスで列を参照したことが原因です。
一般に、Management Studio を使用して列の順序を変更すると、SQL Server で何が起こるかというと、新しい構造の一時テーブルが作成され、データが古いテーブルからその構造に移動され、古いテーブルが削除され、新しいテーブルの名前が変更されます。ご想像のとおり、大きなテーブルがある場合、これはパフォーマンスにとって非常に悪い選択です。My SQL が同じことを行うかどうかはわかりませんが、これが、多くの人が列の並べ替えを避ける理由の 1 つです。select * は本番システムでは決して使用しないでください。適切に設計されたシステムでは、最後に列を追加しても問題ありません。テーブル内の列の順序は、一般的にいじってはいけません。