私の開発者は、ほとんどすべてのテーブルのPKとしてGUIDを使用するようにアプリケーションをセットアップし、SQL ServerはデフォルトでこれらのPKにクラスター化インデックスをセットアップしています。
システムは比較的新しく、最大のテーブルは100万行を少し超えていますが、インデックス作成を検討しており、近い将来必要になる可能性があるため、迅速にスケーリングできるようにしたいと考えています。
したがって、最初の傾向は、クラスター化インデックスを、DateTimeのbigint表現である作成されたフィールドに移動することでした。ただし、CXを一意にする唯一の方法は、GUID列をこのCXに含めることですが、最初に作成された順にします。
これにより、クラスタリングキーが広くなりすぎて、書き込みのパフォーマンスが向上しますか?読み取りも重要ですが、現時点ではおそらく書き込みの方が大きな懸念事項です。
GUIDの主な問題、特に非順次の問題は次のとおりです。
それで、これはあなたの状況にどういう意味ですか?それはあなたのデザインにかかっています。システムが単に書き込みに関するものであり、データの取得について懸念がない場合、Thomas Kによって概説されているアプローチは正確です。ただし、この戦略を実行することにより、そのデータを読み取って保存することで多くの潜在的な問題が発生することを覚えておく必要があります。 Jon Seigel が指摘しているように、より多くのスペースを占有し、本質的にメモリの膨張が発生します。
GUIDに関する主な問題は、GUIDがどれほど必要かです。グローバルな一意性を保証するため、開発者はこれらを気に入っていますが、この種の一意性が必要になることはまれです。ただし、値の最大数が2,147,483,647(4バイトの符号付き整数の最大値)未満の場合は、おそらくキーに適切なデータ型を使用していないことを考慮してください。 BIGINT(8バイト)を使用しても、最大値は9,223,372,036,854,775,807です。一意のキーに自動インクリメント値が必要な場合、これは通常、非グローバルデータベース(および多くのグローバルデータベース)に十分です。
最後に、ヒープとクラスタ化インデックスを使用する限り、純粋にデータを書き込む場合は、挿入のオーバーヘッドを最小限に抑えるため、ヒープが最も効率的です。ただし、SQL Serverのヒープは、データの取得には非常に非効率的です。私の経験では、クラスター化インデックスは、それを宣言する機会がある場合は常に望ましいものです。テーブル(40億以上のレコード)にクラスター化インデックスを追加すると、全体的な選択パフォーマンスが6倍向上するのを確認しました。
追加情報:
GUID OLTPシステム内のキーおよびクラスターとして)には何の問題もありません(テーブルのインデックスが大量にあり、実際には、IDENTITYカラムよりもはるかにスケーラブルです。
GUIDはSQL Serverの大きな問題であると広く信じられています。主に、これは非常に単純に間違っています。実際、GUID約8コアを超えるボックスでの大幅な拡張性:
申し訳ありませんが、あなたの開発者は正しいです。 GUIDについて心配する前に、他のことを心配してください。
ああ、そして最後に:そもそもなぜクラスターインデックスが必要なのですか?懸念があるのがOLTPシステムに小さなインデックスがたくさんある場合、ヒープを用意することをお勧めします。
ここで、断片化(GUIDによって導入される)が読み取りに及ぼす影響)について考えてみましょう。断片化には3つの大きな問題があります。
問題の懸念はスケーラビリティに関するものなので、「ハードウェアを追加するとシステムが高速になる」と定義できます。これらは問題の最小です。それぞれに順番に対処するには
広告1)規模が必要な場合は、I/Oを購入する余裕があります。安価なSamsung/Intel 512GB SSD(数ドル/ GB)でも、100K IOPSをはるかに上回ります。 2ソケットシステムでは、すぐに消費することはありません。それに遭遇した場合、もう1つ購入すれば準備は完了です
広告2)テーブルで削除を行うと、いずれにしてもページ全体が半分になります。そして、そうでない場合でも、メモリは安価であり、最大のOLTP=システム以外のすべてのシステムで-ホットデータはそこに収まるはずです。ページにさらに多くのデータをパックすることは、規模を探しています。
広告3)頻繁にページ分割され、高度にフラグメント化されたデータから構築されたテーブルは、順次入力されるテーブルとまったく同じ速度でランダムI/Oを実行します
結合に関して、OLTPのようなワークロードで見られる可能性のある2つの主要な結合タイプがあります:ハッシュとループです。それぞれを順に見てみましょう:
ハッシュ結合:ハッシュ結合は、小さなテーブルがスキャンされ、より大きなテーブルが通常シークされることを前提としています。小さなテーブルはメモリ内にある可能性が非常に高いため、I/Oはここでは問題になりません。シークがフラグメント化されたインデックスのコストは非フラグメント化されたインデックスと同じであるという事実についてはすでに触れました。
ループ結合:外部テーブルが検索されます。同じ費用
また、多くの不正なテーブルスキャンが行われている可能性もありますが、GUIDは問題ではありません。適切なインデックス付けです。
現在、正当な範囲スキャンが行われている可能性があり(特に外部キーに結合する場合)、この場合、断片化されたデータは、断片化されていないデータと比較して「パック」されていません。しかし、よくインデックス化された3NFデータでどの結合が見られるかを考えてみましょう。
参照するテーブルの主キーへの外部キー参照を持つテーブルからの結合
逆に
Ad 1)この場合、主キーを1回シークします-nを1に結合します。断片化の有無にかかわらず、同じコスト(1回のシーク)
広告2)この場合、同じキーに参加していますが、複数の行を取得する場合があります(範囲シーク)。この場合の結合は1対nです。ただし、探している外部テーブルは、同じキーを探しています。これは、断片化されていないものと同じように、断片化されたインデックスの同じページにあります。
少しの間、これらの外部キーを検討してください。 「完全に」シーケンシャルに主キーを配置した場合でも、そのキーを指すものはすべてシーケンシャルではありません。
もちろん、あなたは仮想マシンでいくつかのSANお金が安くてプロセスが高い銀行で実行しているかもしれません。それからこのアドバイスはすべて失われます。しかしそれがあなたの世界なら、スケーラビリティはおそらくあなたが探しているものではありません-あなたはパフォーマンスと高速/コストを探しています-どちらも違うものです。
トーマス:あなたの主張のいくつかは完全に理にかなっており、私はそれらすべてに同意します。 SSDを使用している場合、最適化対象のバランスは変わります。ランダムvsシーケンシャルは、回転ディスクと同じ議論ではありません。
私は特に、純粋なDBビューをとることはひどく間違っていることに同意します。アプリケーションを遅くしてスケーラブルでないようにすることで改善DBのパフォーマンスはかなり誤ったものになる可能性があります。
IDENTITY(またはシーケンス、またはanythingがDBで生成される)の大きな問題は、作成するためにDBへの往復が必要になるため、非常に遅いことですキー。これによりDBで自動的にボトルネックが発生し、アプリケーションがキーの使用を開始するにはDB呼び出しを行う必要があります。 GUIDを作成すると、キーを作成するためにアプリケーションを使用してこれが解決されます。これはグローバルに一意であることが(定義により)保証されます。したがって、アプリケーションレイヤーはこれを使用して、 DB往復。
しかし、私はGUIDの代わりに使用する傾向がありますここでのデータ型に対する個人的な好みは、アプリによって生成されるグローバルに一意のBIGINTです。これを行うにはどうすればよいですか?最も簡単な例では、小さな、非常に軽量な関数をアプリに追加して、GUIDをハッシュします。ハッシュ関数が高速で比較的速いと仮定します(1つの例については、GoogleのCityHashを参照してください: http://google-opensource.blogspot.in/2011/04/introducing-cityhash.html -確認してくださいすべてのコンパイル手順を正しく行うか、FNV1aのバリアント http://tools.ietf.org/html/draft-eastlake-fnv- を使用して単純なコードを取得)これにより、両方のアプリケーションの利点が得られます生成された一意の識別子と、CPUがより適切に機能する64ビットのキー値。
BIGINTを生成する方法は他にもあり、これらのアルゴの両方でハッシュの衝突の可能性があります-読み取りと意識的な決定を行います。