id のデータ型を選択するときは、データ ストレージ タイプだけでなく、MySQL がこのタイプを計算して比較する方法も考慮する必要があります。たとえば、MySQL は ENUM 型と SET 型を内部的には整数として保存しますが、文字列のシナリオでは文字列として比較します。 ID のデータ型を選択したら、長さや符号の有無などのプロパティを含め、ID を参照する関連データ テーブルのデータ型が一貫しており、完全に一貫していることを確認する必要があります。異なるデータ型を混在させるとパフォーマンスの問題が発生する可能性があります。また、パフォーマンスの問題がない場合でも、比較中に暗黙的にデータ変換が行われると、微妙なエラーが発生する可能性があります。しかし、実際の開発プロセス中にさまざまなデータ型を忘れると、予期しない問題が突然発生する可能性があります。 長さを選択する際には、できるだけ短いフィールド長さを選択し、将来の成長に余裕を持たせることも必要です。たとえば、州を格納するために使用する場合、値は数十個しかありません。このとき、INT ではなく TINYINT を使用する方が適切です。関連テーブルにもこの ID が格納されている場合、効率の差は非常に大きくなります。 ID に適用される一般的なタイプを次に示します。
UUID 値を使用する場合は、「-」文字を削除するか、UNHEX 関数を使用して 16 バイトの数値に変換し、BINARY(16) を使用して保存する必要があります。次に、HEX 関数を使用して 16 進形式で取得できます。 UUID を生成する方法は多数あり、ランダムに分散されるものもあれば、順序付けられているものもありますが、順序付けられたものでも整数ほどパフォーマンスは良くありません。 分散IDソリューションの概要IDはデータの一意の識別子です。従来のアプローチは、UUIDとデータベースの自動増分IDを使用することです。今日、MySQLはますます広く使用され、トランザクションのサポートが必要なため、通常はInnodbストレージエンジンが使用されます。UUIDは長すぎて乱雑であるため、Innodbの主キーとしては適していません。自動増分IDの方が適していますが、ビジネス開発ではデータの量がますます大きくなり、データをテーブルに分割する必要があります。テーブルが分割された後、各テーブルのデータは独自のペースで自動増分され、IDの競合が発生する可能性が高くなります。このとき、一意の ID を生成するための別のメカニズムが必要になります。生成された ID は、分散 ID またはグローバル ID とも呼ばれます。分散 ID を生成するメカニズムを分析してみましょう。 データベース自動増分IDこの方法は、データベースの自動インクリメント ID に基づいています。別のデータベース インスタンスを使用し、このインスタンスに別のテーブルを作成する必要があります。 テーブル構造は次のとおりです。 データベース `SEQID` を作成します。 テーブルSEQID.SEQUENCE_IDを作成します( id bigint(20) unsigned NOT NULL auto_increment, スタブ char(10) NOT NULL デフォルト '' 主キー (id)、 UNIQUE KEY スタブ (スタブ) )ENGINE=MyISAM; 次のステートメントを使用して、自動増分IDを生成および取得できます。 始める; SEQUENCE_ID(スタブ)VALUES('anyword')に置き換えます。 last_insert_id() を選択します。 専念; スタブ フィールドには、ここでは特別な意味はありません。これは、データを挿入する際の利便性のためだけのものです。データを挿入できる場合にのみ、自動増分 ID を生成できます。挿入には replace を使用します。 replace は、まず指定されたスタブと同じ値のデータがあるかどうかを確認します。存在する場合は、まずそれを削除してから挿入します。存在しない場合は、直接挿入します。 分散 ID を生成するこのメカニズムには、別の MySQL インスタンスが必要です。これは実現可能ですが、パフォーマンスと信頼性の点で十分ではありません。業務システムで ID が必要になるたびに、データベースに ID の取得を要求する必要があり、パフォーマンスが低下します。このデータベース インスタンスがオフラインになると、すべての業務システムに影響が及びます。 ; したがって、この方法ではデータにはある程度の信頼性の低さがあります。 データベースマルチマスターモード2 つのデータベースがマスター スレーブ クラスターを形成する場合、通常の状況ではデータベースの信頼性の問題を解決できます。ただし、マスター データベースに障害が発生し、データがスレーブ データベースに時間内に同期されない場合、ID の重複が発生します。このため、マルチマスターモード☞デュアルマスターモードのクラスターを使用できます。つまり、両方の MySQL インスタンスが独立して自動増分 ID を生成できるため、効率が向上します。ただし、他の変更が行われない場合、2 つの MySQL インスタンスは同じ ID を生成する可能性があります。 MySQL インスタンスごとに異なる開始値と自動増分ステップを構成する必要があります。 最初の MySQL インスタンス構成 (mysql_01): set @@auto_increment_offset = 1; -- 開始値 set @@auto_increment_increment = 2; -- ステップ長 2 番目の MySQL インスタンス構成 (mysql_02): set @@auto_increment_offset = 2; -- 開始値 set @@auto_increment_increment = 2; -- ステップ長 上記の設定後、2 つの MySQL インスタンスによって生成される ID シーケンスは次のようになります。 分散 ID を生成するこのソリューションでは、DistributIdService などの新しい分散 ID 生成アプリケーションを追加する必要があります。このアプリケーションは、ビジネス アプリケーションが ID を取得するためのインターフェイスを提供します。ビジネス アプリケーションで ID が必要な場合、RPC を介して DistributIdService を要求します。DistributIdService は、上記の 2 つの MySQL インスタンスから ID をランダムに取得します。 このソリューションを実装すると、MySQL インスタンスの 1 つがオフラインになっても DistributIdService には影響せず、DistributIdService は引き続き別の MySQL を使用して ID を生成できます。 ただし、このソリューションは拡張性に欠けます。2 つの MySQL インスタンスでは不十分で、パフォーマンスを向上させるために新しい MySQL インスタンスを追加する必要がある場合は、面倒になります。 さて、新しいインスタンス mysql_03 を追加したい場合はどうすればよいでしょうか?
数値セグメントモードこのモードはバッチ取得として理解できます。たとえば、DistributIdService がデータベースから ID を取得するときに、複数の ID をバッチで取得してローカルにキャッシュできれば、業務アプリケーションの ID 取得効率が大幅に向上します。 たとえば、DistributIdService がデータベースから ID を取得するたびに、(1,1000] などの数値セグメントを取得します。この範囲は 1000 個の ID を表します。ビジネス アプリケーションが DistributIdService に ID の提供を要求すると、DistributIdService は毎回データベースを要求せずに、ローカルで数値を 1 から増分して返すだけで済みます。ローカルの数値が 1000 に増分されるまで、つまり現在の数値セグメントが使い果たされるまで、データベースにアクセスして次の数値セグメントを取得することはありません。 したがって、データベース テーブルを次のように変更する必要があります。 id_generatorテーブルを作成します( id int(10) NULLではない、 current_max_id bigint(20) NOT NULL COMMENT '現在の最大ID', increment_step int(10) NOT NULL COMMENT '増分ステップ', 主キー (`id`) )ENGINE=InnoDB デフォルト文字セット=utf8; このデータベース テーブルは、自動増分ステップと自動増分 ID の現在の最大値 (つまり、現在適用されている数値セグメントの最後の値) を記録するために使用されます。自動増分ロジックは DistributIdService に移動されたため、データベースではこのロジックは不要になりました。 このソリューションは、データベースに強く依存しなくなりました。データベースが利用できなくなった場合でも、DistributIdService は一定期間データベースのサポートを継続できます。ただし、DistributIdService が再起動されると、ID のセグメントが失われ、ID ホールが発生します。 DistributIdService の高可用性を向上させるには、クラスターが必要です。ビジネスが DistributIdService クラスターに ID の取得を要求すると、クラスターはランダムに DistributIdService ノードを選択して ID を取得します。各 DistributIdService ノードは、同じデータベースに接続されているため、複数の DistributIdService ノードが同時にデータベースに番号セグメントの取得を要求する場合があります。この場合、制御には楽観的ロックが必要です。たとえば、データベース テーブルにバージョン フィールドを追加します。番号セグメントを取得するときは、次の SQL を使用します。 id_generator を更新し、current_max_id=#{newMaxId}、version=version+1 を設定します。version は #{version} です。 DistributIdService では、oldMaxId + ステップ サイズに基づいて newMaxId が計算されるため、上記の更新が成功すれば、数値セグメントが正常に取得されたことになります。 データベース層の高可用性を実現するには、データベースをマルチマスター モードで展開する必要があります。各データベースでは、生成された番号セグメントが重複しないようにする必要があります。そのためには、元のアイデアを使用して、開始値とステップ サイズをデータベース テーブルに追加する必要があります。たとえば、MySQL サーバーが 2 つある場合は、次のようになります。 具体的な実装コードについては、tinyidを参照してください。 スノーフレークアルゴリズムデータベース自己増分 ID モード、データベース マルチマスター モード、および番号セグメント モードの 3 つのモードはすべて自己増分の概念に基づいています。スノーフレーク アルゴリズムの概念は、以下で簡単に理解できます。 基本的な考え方は、分散 ID が固定の長い数値であるということです。長い数値は 8 バイト、つまり 64 ビットを占めます。元の Snowflake アルゴリズムでのビットの割り当ては次のとおりです。
このアルゴリズムのロジックによれば、このアルゴリズムを Java 言語で実装し、ツール メソッドにカプセル化するだけで済みます。その後、各ビジネス アプリケーションはこのツール メソッドを直接使用して分散 ID を取得できます。分散 ID を取得するために別のアプリケーションを構築することなく、各ビジネス アプリケーションが独自の作業マシン ID を持っていることを確認するだけで済みます。また、データベースにも依存しません。 具体的なコード実装 パッケージ com.yeming.tinyid.application; 静的 java.lang.System.* をインポートします。 /** * @著者 イェミン・ガオ * @Description: スノーフレークアルゴリズムの実装* <p> * SnowFlake アルゴリズムは 64 ビット ID を生成するために使用されます。64 ビット ID は長整数で保存でき、分散システムで一意の ID を生成するために使用できます。 * 生成された ID には大まかな順序があります。 この実装では、生成された 64 ビット ID は 5 つの部分に分割できます。 * 0 - 41 ビットのタイムスタンプ - 5 ビットのデータセンター ID - 5 ビットのマシン ID - 12 ビットのシリアル番号 * @date 2020/07/28 16:15 */ パブリッククラスSnowFlake { /** * 開始タイムスタンプ */ プライベート静的最終long START_STMP = 1480166465631L; /** * マシンIDが占める桁数 */ プライベート静的最終long MACHINE_BIT = 5; /** * データセンターが占有するビット数 */ プライベート静的最終長いDATACENTER_BIT = 5; /** * シリアル番号の桁数 */ プライベート静的最終長いSEQUENCE_BIT = 12; /** * マシンIDの最大値*/ プライベート静的最終long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT); /** * データセンターの最大値 */ プライベート静的最終long MAX_DATACENTER_NUM = ~(-1L << DATACENTER_BIT); /** * 最大シリアル番号値*/ プライベート静的最終long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT); /** *各パーツの左への変位*/ プライベート静的最終ロング MACHINE_LEFT = SEQUENCE_BIT; プライベート静的最終長い DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; プライベート静的最終long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; private long datacenterId; //データセンターprivate long machineId; //マシンIDprivate long sequence = 0L; //シリアル番号private long lastStmp = -1L; //最終タイムスタンプprivate SnowFlake(long datacenterId, long machineId) { データセンターID > MAX_DATACENTER_NUM || データセンターID < 0 の場合 { throw new IllegalArgumentException("datacenterId は MAX_DATACENTER_NUM より大きく、0 より小さくすることはできません"); } マシンID > MAX_MACHINE_NUM || マシンID < 0 の場合 { throw new IllegalArgumentException("machineId は MAX_MACHINE_NUM より大きく、0 より小さくすることはできません"); } this.datacenterId = データセンターId; this.machineId = マシンID; } /** * 次のIDを生成する * * @戻り値 long */ プライベート同期された長いnextId(){ 長いcurrStmp = System.currentTimeMillis(); (現在のスタンプ<最後のスタンプ)の場合{ throw new RuntimeException("時計が逆方向に動きました。ID の生成を拒否します"); } (現在のスタンプ == 最後のスタンプ)の場合{ //同じミリ秒内に、シーケンス番号が自動的に増加します。sequence = (sequence + 1) & MAX_SEQUENCE; // 同じミリ秒内のシーケンスの数が最大値に達した if (sequence == 0L) { currStmp = getNextMill(); } } それ以外 { //異なるミリ秒では、シーケンス番号は0に設定されます シーケンス = 0L; } 最後のStmp = currStmp; return (currStmp - START_STMP) << TIMESTMP_LEFT //タイムスタンプ部分 | datacenterId << DATACENTER_LEFT //データセンター部分 | machineId << MACHINE_LEFT //マシンID部分 | sequence; //シリアル番号部分} プライベートlong getNextMill() { ロングミル = System.currentTimeMillis(); while (ミル <= lastStmp) { ミル = System.currentTimeMillis(); } リターンミル; } パブリック静的voidメイン(String[] args) { スノーフレーク snowFlake = new SnowFlake(2, 3); // データセンター識別子の最大値 long maxDatacenterNum = ~(-1L << DATACENTER_BIT); //マシン識別子の最大値 long maxMachineNum = ~(-1L << MACHINE_BIT); // シーケンス番号の最大値 long maxSequence = ~(-1L << SEQUENCE_BIT); out.println("データセンター ID の最大値: " + maxDatacenterNum + "; マシン ID の最大値: " + maxMachineNum + "; シーケンス番号の最大値: " + maxSequence); (int i = 0; i < (1 << 12); i++) の場合 { out.println(snowFlake.nextId()); } } } スノーフレーク アルゴリズムとは、次のものを指します。
上記は、MySQL ID に適切なデータ型を選択する方法の詳細です。MySQL ID に適切なデータ型を選択する方法の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
>>: Springboot および Vue プロジェクトの Docker デプロイメントの実装手順
目次1 違い1.1 スペース占有1.2 表現範囲1.3 タイムゾーン2 テスト3つの選択肢MySQL...
目次1. 計算プロパティ構文: 1. 省略形:文法: 2. 文章を完成させる: 2. モニタリング(...
この記事では、検証コード機能を実装するためのvue+spring bootの具体的なコードを例として...
まず、データベース パーティショニングとは何でしょうか?以前、MySQL のテーブル パーティショニ...
この記事の例では、参考までに、シンプルなショッピングカートモジュールを実装するためのjsの具体的なコ...
データベースからクエリする必要があるテーブルに数万件のレコードがある場合、すべての結果を一度にクエリ...
みなさんこんにちは。私は梁旭です。 Linux を使用するときに、計算を行う必要がある場合があり、そ...
まず、公式ウェブサイト http://dev.mysql.com/downloads/mysql/ ...
データとコンピューターに対してできる最善のことは、それらを安全に保つことです。アップデートを有効にす...
次のような疑問が湧くかもしれません。MySQLをローカル (自分のコンピュータ) にインストールした...
目次1. カプセル化API 2. グローバルツールコンポーネントを登録する3. グローバル関数をカプ...
目次実装効果図依存関係をインストールするカスタムツリーコントロールその他の実装要約するVueでは、要...
目次序文sql_mode の説明最も重要なオプションすべてのオプション要約する序文前回の記事「MyS...
フロントエンドプロジェクトのパッケージ化.env.productionを見つけて、自分のIPまたはド...
プロジェクトシナリオ: Dark Horse Vueプロジェクト管理の実践、製品分類の取得、拡張バー...