Sequential Guidのパフォーマンスは、標準のGuidよりも向上していますか?

StackOverflow https://stackoverflow.com/questions/170346

  •  05-07-2019
  •  | 
  •  

質問

データベース内で主キーとして使用された場合、誰かがシーケンシャルガイドと標準ガイドのパフォーマンスを測定したことがありますか?

役に立ちましたか?

解決

GUIDとシーケンシャルGUID



典型的なパターンは、テーブルのPKとしてGuidを使用することですが、他の議論で言及されているように( GUID / UUIDデータベースキーの利点と欠点) いくつかのパフォーマンスの問題があります。

これは典型的なGUIDシーケンスです

f3818d69-2552-40b7-a403-01a6db4552f7
    7ce31615-fafb-42c4-b317-40d21a6a3c60
    94732fc7-768e-4cf2-9107-f0953f6795a5
    

この種のデータの問題は次のとおりです。<!> lt;
    -

  • 値の広い分布
  • ほぼランダムなもの
  • インデックスの使用は非常に、非常に、非常に悪いです
  • たくさんの葉が動く
  • ほぼすべてのPKは少なくとも 非クラスター化インデックス
  • 問題はOracleと SQL Server



可能な解決策は、次のように生成されるシーケンシャルGUIDを使用することです。
    cc6466f7-1066-11dd-acb6-005056c00008
    cc6466f8-1066-11dd-acb6-005056c00008
    cc6466f9-1066-11dd-acb6-005056c00008


C#コードから生成する方法:

[DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(out Guid guid);

public static Guid SequentialGuid()
{
    const int RPC_S_OK = 0;
    Guid g;
    if (UuidCreateSequential(out g) != RPC_S_OK)
        return Guid.NewGuid();
    else
        return g;
}


利点

  • インデックスのより良い使用
  • クラスター化されたキーの使用を許可する NLBシナリオで検証済み)
  • ディスク使用量が少ない
  • パフォーマンスが20〜25%向上 最低費用



実生活の測定: シナリオ:

  • UniqueIdentifierとして保存されたガイド SQL Serverのタイプ
  • OracleでCHAR(36)として保存されたガイド
  • 多数の挿入操作、バッチ処理 単一のトランザクションで一緒に
  • 1から100の挿入物に依存 テーブルの上
  • 一部のテーブル<!> gt; 1,000万行



臨床検査<!>#8211; SQL Server

VS2008テスト、10人の同時ユーザー、思考時間なし、リーフテーブルのバッチに600個の挿入があるベンチマークプロセス
標準ガイド
平均処理時間: 10.5
平均2番目のリクエスト: 54.6
平均それぞれ時間: 0.26

シーケンシャルガイド
平均処理時間: 4.6
平均2番目のリクエスト: 87.1
平均それぞれ時間: 0.12

Oracleでの結果(申し訳ありませんが、テストに別のツールが使用されています)1.327.613 Guid PKを使用したテーブルへの挿入

標準ガイド 0.02 秒。各挿入の経過時間、 2.861 秒。 CPU時間の合計、 31.049 秒。経過

シーケンシャルガイド 0.00 秒。各挿入の経過時間、 1.142 秒。 CPU時間の合計、 3.667 秒。経過

6.4 ミリ秒の 62.415 秒の待機イベントから 120 ミリ秒の< strong> 11.063 秒。

すべてのシーケンシャルGUIDを推測できることを確認することが重要です。したがって、セキュリティが懸念される場合、標準のGUIDを使用したまま使用することはお勧めできません。
短くするには... PKとしてGuidを使用する場合、UIから前後に渡されないたびにシーケンシャルguidを使用すると、操作が高速化され、実装に費用はかかりません。

他のヒント

ここで何かが足りないかもしれませんが(私がいる場合はお気軽に修正してください)、主キーにシーケンシャルGUID / UUIDを使用してもほとんど利点がありません。

自動インクリメント整数でGUIDまたはUUIDを使用するポイントは次のとおりです。

  • これらは、データベースに接続せずにどこでも作成できます
  • これらは、アプリケーション内で完全に一意の識別子です(UUIDの場合、普遍的に一意です)
  • 1つの識別子が与えられた場合、巨大なキースペースのブルートフォース以外では、次または前(または他の任意の有効な識別子)を推測する方法はありません。

残念ながら、あなたの提案を使用すると、それらのすべてを失います。

それで、はい。 GUIDを改善しました。しかし、その過程で、そもそもそれらを使用するほとんどすべての理由を捨ててしまいました。

パフォーマンスを本当に改善したい場合は、標準の自動インクリメント整数プライマリキーを使用します。これは、あなたが説明した(およびそれ以上の)すべての利点を提供する一方で、ほぼすべての点で「シーケンシャルガイド」よりも優れています。

これはおそらくあなたの質問に具体的に答えないので忘却にダウンモディドされます(あなたがすぐに答えられるように慎重に作成されているようです)が、提起することははるかに重要なポイントだと思います

massimogentiliniがすでに述べたように、UuidCreateSequentialを使用するとき(コードでGUIDを生成するとき)にパフォーマンスを改善できます。しかし、事実は欠落しているようです:SQL Server(少なくともMicrosoft SQL 2005/2008)は同じ機能を使用しますが、GUIDの比較/順序は.NETとSQL Serverで異なります。 GUIDが正しく順序付けられないためです。 SQLサーバー用に正しく順序付けられたGUIDを生成するには(順序付け)、以下を実行する必要があります(比較の詳細):

[System.Runtime.InteropServices.DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(byte[] buffer);

static Guid NewSequentialGuid() {

    byte[] raw = new byte[16];
    if (UuidCreateSequential(raw) != 0)
        throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error());

    byte[] fix = new byte[16];

    // reverse 0..3
    fix[0x0] = raw[0x3];
    fix[0x1] = raw[0x2];
    fix[0x2] = raw[0x1];
    fix[0x3] = raw[0x0];

    // reverse 4 & 5
    fix[0x4] = raw[0x5];
    fix[0x5] = raw[0x4];

    // reverse 6 & 7
    fix[0x6] = raw[0x7];
    fix[0x7] = raw[0x6];

    // all other are unchanged
    fix[0x8] = raw[0x8];
    fix[0x9] = raw[0x9];
    fix[0xA] = raw[0xA];
    fix[0xB] = raw[0xB];
    fix[0xC] = raw[0xC];
    fix[0xD] = raw[0xD];
    fix[0xE] = raw[0xE];
    fix[0xF] = raw[0xF];

    return new Guid(fix);
}

またはこのリンクまたはこのリンク

シーケンシャルGUIを使用する必要がある 場合、SQL Server 2005はNEWSEQUENTIALID()関数を使用してそれらを生成します。

GUIdsの基本的な使用法は、推測できないキー(または代替キー)を生成することなので(たとえば、GETで推測されたキーを渡すことを避けるため)、どのように適用できるかわかりませんそれらはとても簡単に推測されるからです。

MSDN から:

  

重要:
  プライバシーが懸念される場合は、この機能を使用しないでください。それ   の値を推測することが可能です   次に生成されるGUID、したがって、   そのGUIDに関連付けられたデータにアクセスします。

この記事を参照: ( http://www.shirmanov.com/2010/05/generated- newsequentialid-compatible.html

MSSqlはこの同じ関数を使用してNewSequencialIdsを生成しますが (UuidCreateSequential(out Guid guid))、MSSQLは3番目と4番目のバイトパターンを反転しますが、コードでこの関数を使用した場合と同じ結果は得られません。 Shirmanovは、MSSQLが作成する結果とまったく同じ結果を取得する方法を示します。

Jimmy Nilssonによる COMB をご覧ください:GUIDの一種いくつかのビットがタイムスタンプのような値に置き換えられています。これは、COMBを順序付けできることを意味し、主キーとして使用すると、新しい値を挿入するときにインデックスページの分割が少なくなります。

uniqueidentifier(GUID)を主キーとして使用しても大丈夫ですか?

OK、私はついに自分で設計と生産のこの段階に到達しました。

上位32ビットがミリ秒単位のUnix時間のビット33から1に基づいているCOMB_GUIDを生成します。したがって、2ミリ秒ごとに93ビットのランダム性があり、上位ビットのロールオーバーは106年ごとに発生します。 COMB_GUID(またはタイプ4 UUID)の実際の物理的表現は、128ビットのbase64エンコードバージョンであり、22文字の文字列です。

postgresに挿入する場合、完全にランダムなUUIDとCOMB _GUIDの間の速度の比率は、COMB_GUIDにとって有益なものです。 COMB_GUIDは、100万件のレコードテストを行うため、複数のテストでハードウェア上で 2X 速くなります。レコードには、id(22文字)、文字列フィールド(110文字)、倍精度、およびINTが含まれます。

ElasticSearchでは、インデックス作成の2つの間に識別可能な違いはありません。コンテンツが時間に関連してフィードされる場合、またはコンテンツが IS 時間に関連して部分的になるようにidフィールドで事前ソートできるため、コンテンツがチェーン内のBTREEインデックスに行く場合、COMB_GUIDSを引き続き使用します順次、高速化します。

かなり興味深い。 COMB_GUIDを作成するJavaコードは次のとおりです。

import java.util.Arrays;
import java.util.UUID;
import java.util.Base64; //Only avail in Java 8+
import java.util.Date;

import java.nio.ByteBuffer; 

    private ByteBuffer babuffer = ByteBuffer.allocate( (Long.SIZE/8)*2 );
private Base64.Encoder encoder = Base64.getUrlEncoder();
public  String createId() {
    UUID uuid = java.util.UUID.randomUUID();
        return uuid2base64( uuid );
}

    public String uuid2base64(UUID uuid){ 

        Date date= new Date();
        int intFor32bits;
        synchronized(this){
        babuffer.putLong(0,uuid.getLeastSignificantBits() );
        babuffer.putLong(8,uuid.getMostSignificantBits() );

                long time=date.getTime();
        time=time >> 1; // makes it every 2 milliseconds
                intFor32bits = (int) time; // rolls over every 106 yers + 1 month from epoch
                babuffer.putInt( 0, intFor32bits);

    }
        //does this cause a memory leak?
        return encoder.encodeToString( babuffer.array() );
    }

}

Entity Frameworkを使用して、Guid(クラスター化および非クラスター化)、Sequential Guid、int(Identity / autoincrement)の違いを測定しました。シーケンシャルガイドは、アイデンティティを持つintと比較して驚くほど高速でした。 シーケンシャルガイドの結果とコードはこちら

一意のキーが推測可能かどうかはわかりませんが、Web UIまたは他の部分からそれらを渡すこと自体は悪い習慣のようで、セキュリティ上の懸念がある場合は、 guidは物事を改善できます(これが問題である場合は、フレームワークの適切な暗号化機能を使用して実際の乱数ジェネレーターを使用します)。
他の項目は私のアプローチでカバーされており、シーケンシャルGUIDはDBアクセスを必要とせずにコードから生成でき(Windowsの場合のみ)、時間と空間が一意です。
そして、はい、PKのGuidsを選択した人々にデータベースの使用を改善する方法を提供するために、それに答える目的で質問が提起されました(私の場合、顧客はサーバーを変更せずにはるかに高いワークロードを維持することができました)。

セキュリティ上の懸念は多いようです。この場合、Sequential Guidを使用しないでください。または、UIから前後に渡されるPKの標準Guidを使用してください。常に絶対的な真実はないので、これを反映するためにメインの回答も編集しました。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top