MySQLの列の順序をFIRSTとAFTERで変更できることは知っていますが、なぜわざわざしたいのでしょうか。優れたクエリはデータを挿入するときに列に明示的に名前を付けるので、テーブル内の列の順序を気にする理由は本当にありますか?
回答:
列の順序は、SQL Server、Oracle、MySQLにまたがって、私が調整したいくつかのデータベースに大きなパフォーマンスの影響を与えました。この投稿には経験則があります:
パフォーマンスの違いの例は、インデックスルックアップです。データベースエンジンは、インデックス内のいくつかの条件に基づいて行を検索し、行アドレスを取得します。ここで、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
、大行の場合には、AROW CHAINING
発生する可能性があります。
ROW CHANING
は、1つのブロックに収まらない行を分割し、リンクリストに接続された複数のブロックにまたがっています。
最初のブロックに収まらなかった後続の列を読み取るには、リンクリストをトラバースする必要があり、追加のI/O
操作が発生します。
参照このページをの説明のためROW CHAINING
にありますOracle
:
そのため、頻繁に使用する列をテーブルの先頭に配置し、頻繁に使用しない列、または頻繁に使用する列をNULL
テーブルの末尾に配置する必要があります。
重要な注意点:
もしこの答えのような、それのために投票したい場合は、またのために投票してください@Andomar
の答え。
彼は同じことを答えましたが、理由もなく反対票を投じられたようです。
前の仕事でのOracleトレーニング中に、DBAは、null許容でない列をすべてnull許容列の前に配置することが有利であると提案しました... TBH理由の詳細は覚えていませんが。それとも、更新される可能性が高いのは最後に行くべきだったのでしょうか?(行が拡張された場合、行を移動する必要があるのを延期するかもしれません)
一般的に、それは何の違いももたらさないはずです。あなたが言うように、クエリは「select *」からの順序に依存するのではなく、常に列自体を指定する必要があります。それらを変更できるDBを私は知りません...まあ、あなたがそれを言うまで、MySQLがそれを許可したことを知りませんでした。
正しく作成されていないアプリケーションの中には、列名ではなく列の順序/インデックスに依存しているものがあります。あるべきではありませんが、実際に起こります。列の順序を変更すると、そのようなアプリケーションが機能しなくなります。
いいえ、SQLデータベーステーブルの列の順序は、表示/印刷の目的を除いて、まったく関係ありません。列の順序を変更しても意味がありません。ほとんどのシステムでは、その方法さえ提供されていません(古いテーブルを削除して、新しい列の順序で再作成する場合を除く)。
マーク
編集:リレーショナルデータベースのウィキペディアのエントリから、列の順序が問題になることはないことを明確に示している関連部分があります。
リレーションは、nタプルのセットとして定義されます。数学とリレーショナルデータベースモデルの両方で、セットはアイテムの順序付けられていないコレクションですが、一部のDBMSはデータに順序を課します。数学では、タプルには順序があり、複製が可能です。EF Coddは当初、この数学的定義を使用してタプルを定義しました。その後、関係に基づくコンピューター言語では、順序付けの代わりに属性名を使用する方が(一般的に)はるかに便利であるというのは、EFコッドの優れた洞察の1つでした。この洞察は今日でも使用されています。
よくあることですが、最大の要因は、システムで作業しなければならない次の人です。最初に主キー列、次に外部キー列、次にシステムにとって重要/重要度の高い順に残りの列を配置しようとしています。
UNIONを頻繁に使用する場合は、順序に関する規則があると、列の照合が簡単になります。
前述のように、パフォーマンスに関する潜在的な問題は多数あります。私はかつてデータベースで作業しましたが、クエリでそれらの列を参照しなかった場合、最後に非常に大きな列を配置するとパフォーマンスが向上しました。どうやら、レコードが複数のディスクブロックにまたがっている場合、データベースエンジンは、必要なすべての列を取得すると、ブロックの読み取りを停止する可能性があります。
もちろん、パフォーマンスへの影響は、使用しているメーカーだけでなく、バージョンにも大きく依存します。数か月前、Postgresが「いいね」の比較にインデックスを使用できないことに気づきました。つまり、「 'M%'のような列」と書いた場合、Mにスキップして、最初のNが見つかったときに終了するほど賢くはありませんでした。「between」を使用するように一連のクエリを変更する予定でした。次に、Postgresの新しいバージョンを入手し、それが同様のものをインテリジェントに処理しました。クエリを変更することができなかったのはうれしいです。明らかにここでは直接関係ありませんが、私のポイントは、効率を考慮するために行うことはすべて、次のバージョンでは廃止される可能性があるということです。
私はデータベーススキーマを読み取って画面を作成する汎用コードを日常的に作成しているため、列の順序はほとんどの場合非常に重要です。同様に、私の「レコードの編集」画面は、ほとんどの場合、スキーマを読み取ってフィールドのリストを取得し、それらを順番に表示することによって構築されます。列の順序を変更しても、プログラムは機能しますが、表示がユーザーにとって奇妙な場合があります。同様に、都市/住所/郵便番号/名前/州ではなく、名前/住所/都市/州/郵便番号が表示されることを期待します。もちろん、列の表示順序をコードや制御ファイルなどに入れることはできますが、列を追加または削除するたびに、制御ファイルを更新することを忘れないでください。私は一度物事を言うのが好きです。また、編集画面が純粋にスキーマから構築されている場合、新しいテーブルを追加するということは、ゼロ行のコードを記述してそのテーブルの編集画面を作成することを意味します。これは非常に便利です。(まあ、実際には、通常、一般的な編集プログラムを呼び出すためにメニューにエントリを追加する必要があります。例外が多すぎて実用的ではないため、一般的な「更新するレコードを選択する」をあきらめました。 。)
明らかなパフォーマンスチューニングを超えて、列を並べ替えると(以前は機能していた)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コマンドを修正してデフォルト値を含めることはできますが、列の並べ替えが原因で機能したクエリが機能しなくなったため、頭が痛くなりました。
一般に、SQL ServerでManagementStudioを使用して列の順序を変更すると、新しい構造で一時テーブルが作成され、古いテーブルからその構造にデータが移動され、古いテーブルが削除され、新しいテーブルの名前が変更されます。ご想像のとおり、テーブルが大きい場合、これはパフォーマンスにとって非常に悪い選択です。My SQLが同じことをするかどうかはわかりませんが、それが私たちの多くが列の並べ替えを避ける理由の1つです。select *は実動システムでは決して使用されるべきではないので、最後に列を追加することは、適切に設計されたシステムにとって問題ではありません。表の列の順序は、一般的に混乱してはなりません。
2002年、Bill Thorsteinsonは、列を並べ替えることによってMySQLクエリを最適化するための提案をHewlettPackardフォーラムに投稿しました。それ以来、彼の投稿は文字通りコピーされ、インターネット上に少なくとも100回貼り付けられており、多くの場合、引用されていません。彼を正確に引用するには...
一般的な経験則:
- 最初に主キー列。
- 次の外部キー列。
- 次によく検索される列。
- 後で頻繁に更新される列。
- null許容列は最後です。
- 使用頻度の低いNULL可能列の後に、使用頻度の低いNULL可能列。
- 他の列がほとんどない独自のテーブルのブロブ。
出典:HPフォーラム。
しかし、その投稿は2002年にすべて行われたものです。 このアドバイスは、MySQL 5.1がリリースされる6年以上前の、MySQLバージョン3.23に対するものでした。 また、参考文献や引用はありません。それで、ビルは正しかったですか?そして、ストレージエンジンはこのレベルでどの程度正確に機能しますか?
オラクル認定の専門家であるマーティン・ザーンを、オラクルの行の連鎖と移行の秘密に関する記事で引用すると...
連鎖した行は、私たちに異なる影響を与えます。ここでは、必要なデータによって異なります。2つのブロックにまたがる2つの列を持つ行がある場合、クエリは次のようになります。
SELECT column1 FROM table
column1がブロック1にある場合、「テーブルフェッチの継続行」は発生しません。実際にはcolumn2を取得する必要はなく、チェーンされた行を完全に追跡することはありません。一方、私たちが求める場合:
SELECT column2 FROM table
列2は行チェーンのためにブロック2にあり、実際には「テーブルフェッチの継続行」が表示されます。
記事の残りの部分はかなり良い読み物です!しかし、ここでは、当面の質問に直接関連する部分のみを引用しています。
18年以上後、私はそれを言わなければなりません:ありがとう、ビル!