連続したGUIDと断片化
-
27-09-2019 - |
質問
私は、順次GUIDが通常のGUIDよりも優れたパフォーマンスを理解しようとしています。
それは、通常のGUIDを使用すると、インデックスがGUIDの最後のバイトを使用してソートするためですか?ランダムなので、新しいデータを挿入するためにデータを別のページに移動することが多いため、断片化とページの分割がたくさんありますか?
シーケンシャルガイドサインそれは、ページの分割と断片化を大いに減らします。
私の理解は正しいですか?
誰かがこのテーマにもっと光を当てることができれば、とても感謝しています。
ありがとうございました
編集:
シーケンシャルGUID = newSequentionID()、
通常のguid = newid()
解決
あなたはあなたの質問でそれをすべて言った。
シーケンシャルGUID /プライマリキーを使用すると、テーブルの端に新しい行が一緒に追加され、SQLサーバーにとって簡単になります。比較すると、ランダムなプライマリキーは、新しいレコードをテーブルのどこにでも挿入できることを意味します - テーブルがキャッシュにある最後のページの可能性はかなりありそうです(それがすべての読み取りが進んでいる場合)が、キャッシュ内にあるテーブルの中央にあるランダムなページはかなり低いため、追加のIOが必要です。
その上、テーブルの中央に行を挿入すると、余分な列を挿入するのに十分なスペースがない可能性があります。この場合、SQL Serverはレコードの余地を作成するために追加の高価なIO操作を実行する必要があります。これを回避する唯一の方法は、データの間にギャップが散らばっており、追加のレコードを挿入できるようにすることです(充填要因)、それ自体がパフォーマンスの問題を引き起こします。これは、データがより多くのページに広がっているため、テーブル全体にアクセスするためにより多くのIOが必要です。
他のヒント
私はこのトピックに関するキンバリー・L・トリップの知恵に延期します。
しかし、クライアントで生成された値(.NETを使用)またはnewID()関数によって(SQL Serverで)生成されるようなシーケンシャルではないガイドは、主に恐ろしく悪い選択です - 主に断片化のために、ベーステーブルで作成されますが、サイズのためにも作成されます。それは不必要に幅が広いです(INTベースのIDの4倍です。これにより、20億(実際、40億)のユニークな列を提供できます)。また、20億以上が必要な場合は、いつでもBigint(8バイトINT)を使用して263-1列を取得できます。
全体像を視覚化します utilという名前 オストレス 使用される可能性があります。たとえば、2つのテーブルを作成できます 正常 PKとしてのGUID、シーケンシャルガイドを備えた別のGUID:
-- normal one
CREATE TABLE dbo.YourTable(
[id] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_YourTable] PRIMARY KEY NONCLUSTERED (id)
);
-- sequential one
CREATE TABLE dbo.YourTableSeq(
[id] [uniqueidentifier] NOT NULL CONSTRAINT [df_yourtable_id] DEFAULT (newsequentialid()),
CONSTRAINT [PK_YourTableSeq] PRIMARY KEY NONCLUSTERED (id)
);
次に、特定のユーティを使用すると、インデックスの断片化に関する統計を選択した挿入物を数回実行します。
ostress -Slocalhost -E -dYourDB -Q"INSERT INTO dbo.YourTable VALUES (NEWID()); SELECT count(*) AS Cnt FROM dbo.YourTable; SELECT AVG_FRAGMENTATION_IN_PERCENT AS AvgPageFragmentation, PAGE_COUNT AS PageCounts FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, N'LIMITED') DPS INNER JOIN sysindexes SI ON DPS.OBJECT_ID = SI.ID AND DPS.INDEX_ID = SI.INDID WHERE SI.NAME = 'PK_YourTable';" -oE:\incoming\TMP\ -n1 -r10000
ostress -Slocalhost -E -dYourDB -Q"INSERT INTO dbo.YourTableSeq DEFAULT VALUES; SELECT count(*) AS Cnt FROM dbo.YourTableSeq; SELECT AVG_FRAGMENTATION_IN_PERCENT AS AvgPageFragmentation, PAGE_COUNT AS PageCounts FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, N'LIMITED') DPS INNER JOIN sysindexes SI ON DPS.OBJECT_ID = SI.ID AND DPS.INDEX_ID = SI.INDID WHERE SI.NAME = 'PK_YourTableSeq';" -oE:\incoming\TMP\ -n1 -r10000
次に、ファイルe: encoming tmp query.outで統計が見つかります。私の結果は次のとおりです。
"Normal" GUID:
Records AvgPageFragmentation PageCounts
----------------------------------------------
1000 87.5 8
2000 93.75 16
3000 96.15384615384616 26
4000 96.875 32
5000 96.969696969696969 33
10000 98.571428571428584 70
Sequential GUID:
Records AvgPageFragmentation PageCounts
----------------------------------------------
1000 83.333333333333343 6
2000 63.636363636363633 11
3000 41.17647058823529 17
4000 31.818181818181817 22
5000 25.0 28
10000 12.727272727272727 55
挿入された順次GUIDが挿入されていることでわかるように、挿入操作が新しいページの割り当てがまったくなくなるため、インデックスはそれほど断片化されていません。