私は約 8 年前にアプリ用にこのようなシステムを構築しましたが、アプリの使用が増えるにつれて進化した方法をいくつか共有できます。
まず、任意のデバイスからのすべての変更 (挿入、更新、または削除) を「履歴」テーブルに記録することから始めました。たとえば、誰かが「contact」テーブルの電話番号を変更した場合、システムは contact.phone フィールドを編集し、action=update、table=contact、field=phone、record=[ の履歴レコードも追加します。連絡先 ID]、値 = [新しい電話番号]。その後、デバイスが同期するたびに、前回の同期以降の履歴項目がダウンロードされ、ローカル データベースに適用されます。これは、前述の「トランザクション レプリケーション」パターンのように思えます。
1 つの問題は、アイテムが異なるデバイスで作成される可能性がある場合に、ID を一意に保つことです。これを始めたときは UUID について知らなかったので、自動インクリメント ID を使用し、デバイスからアップロードされた新しい ID をチェックし、競合があれば一意の ID に変更するために中央サーバーで実行される複雑なコードを書きました。ソース デバイスにローカル データベースの ID を変更するように指示します。新しいレコードの ID を変更するだけならそれほど悪くはありませんが、たとえば contact テーブルに新しいアイテムを作成し、次に event テーブルに新しい関連アイテムを作成すると、外部キーも必要になります。チェックして更新します。
最終的に、UUID でこれを回避できることを知りましたが、それまでにデータベースがかなり大きくなり、UUID を完全に実装するとパフォーマンスの問題が発生するのではないかと心配しました。そのため、完全な UUID を使用する代わりに、ランダムに生成された 8 文字の英数字キーを ID として使用するようにし、競合を処理するために既存のコードをそのまま残しました。私の現在の 8 文字のキーと UUID の 36 文字の間のどこかに、不必要に肥大化することなく競合を排除するスイート スポットがあるに違いありませんが、競合解決コードを既に持っているため、それを試すことは優先事項ではありませんでした。 .
次の問題は、履歴テーブルがデータベースの残りの部分よりも約 10 倍大きいことでした。これにより、ストレージのコストが高くなり、履歴テーブルのメンテナンスが苦痛になる可能性があります。そのテーブル全体を保持することで、ユーザーは以前の変更をロールバックできますが、やり過ぎのように感じ始めました。そのため、デバイスが最後にダウンロードした履歴項目が履歴テーブルに存在しなくなった場合、サーバーは最近の履歴項目を提供せず、代わりにすべてのデータを含むファイルを提供する同期プロセスにルーチンを追加しましたそのアカウント。次に、90 日以上経過した履歴項目を削除する cronjob を追加しました。これは、ユーザーが 90 日未満の変更を引き続きロールバックできることを意味し、少なくとも 90 日ごとに 1 回同期する場合、更新は以前と同様にインクリメンタルになります。ただし、90日以上待つと、
この変更により、履歴テーブルのサイズがほぼ 90% 縮小されたため、履歴テーブルを維持しても、データベースのサイズは 10 倍ではなく 2 倍になるだけです。このシステムのもう 1 つの利点は、必要に応じて履歴テーブルがなくても同期が機能することです。一時的にオフラインにするメンテナンスを行う必要がある場合などです。または、異なる価格帯のアカウントに対して異なるロールバック期間を提供することもできます。ダウンロードする変更が 90 日以上ある場合は、通常、完全なファイルの方が増分形式よりも効率的です。
今日からやり直す場合は、ID 競合チェックをスキップして、競合を排除するのに十分なキーの長さを目指します。念のため、何らかのエラー チェックを行います。(YouTube は 11 文字のランダム ID を使用しているようです。) 履歴テーブルと、最近の更新の増分ダウンロードまたは必要な場合の完全ダウンロードの組み合わせは、うまく機能しています。