Yaklaşık 8 yıl önce bir uygulama için böyle bir sistem oluşturdum ve uygulama kullanımı arttıkça evrimleştiği birkaç yolu paylaşabilirim.
Herhangi bir cihazdaki her değişikliği (ekleme, güncelleme veya silme) "geçmiş" tablosuna kaydederek başladım. Örneğin, birisi "kişi" tablosundaki telefon numarasını değiştirirse, sistem contact.phone alanını düzenler ve ayrıca action = update, field = phone, record = [kişi kimliği], değer = [yeni telefon numarası]. Daha sonra bir cihaz her senkronize edildiğinde, son senkronizasyondan bu yana geçmiş öğelerini indirir ve bunları yerel veritabanına uygular. Bu, yukarıda açıklanan "işlem çoğaltma" düzeni gibi görünür.
Bir sorun, öğeler farklı cihazlarda oluşturulabildiğinde kimlikleri benzersiz tutmaktır. Bunu başlattığımda UUID'leri bilmiyordum, bu yüzden otomatik artan kimlikleri kullandım ve cihazlardan yüklenen yeni kimlikleri kontrol etmek, bir çakışma varsa benzersiz bir kimliğe değiştirmek için merkezi sunucuda çalışan kıvrımlı bir kod yazdım ve kaynak aygıta yerel veritabanındaki kimliği değiştirmesini söyleyin. Sadece yeni kayıtların kimliklerini değiştirmek o kadar da kötü değildi, ancak örneğin, kişi tablosunda yeni bir öğe oluşturursam, olay tablosunda yeni bir ilgili öğe oluşturursam, şimdi de ihtiyacım olan yabancı anahtarlarım var kontrol edin ve güncelleyin.
Sonunda UUID'lerin bundan kaçınabileceğini öğrendim, ancak o zamana kadar veritabanım oldukça genişledi ve tam bir UUID uygulamasının bir performans sorunu yaratacağından korktum. Bu yüzden tam UUID'leri kullanmak yerine, kimlik olarak rastgele oluşturulmuş 8 karakterli alfasayısal anahtarları kullanmaya başladım ve çakışmaları çözmek için mevcut kodumu yerinde bıraktım. Mevcut 8 karakterli anahtarlarım ve bir UUID'nin 36 karakteri arasında bir yerde, gereksiz şişkinlik olmadan çatışmaları ortadan kaldıracak tatlı bir nokta olmalı, ancak zaten çatışma çözümleme koduna sahip olduğum için, bunu denemek bir öncelik değildi .
Sonraki sorun, geçmiş tablosunun veritabanının geri kalanından yaklaşık 10 kat daha büyük olmasıydı. Bu, depolamayı pahalı hale getirir ve geçmiş tablosundaki herhangi bir bakım acı verici olabilir. Bu tablonun tamamını tutmak, kullanıcıların önceki değişiklikleri geri almasına izin verir, ancak bu aşırı doldurma gibi hissetmeye başlar. Bu yüzden senkronizasyon işlemine bir rutin ekledim; burada bir cihazın en son indirildiği geçmiş öğesi artık geçmiş tablosunda yoksa, sunucu ona son geçmiş öğelerini vermez, bunun yerine tüm verileri içeren bir dosya verir. o hesap. Sonra 90 günden eski tarih öğelerini silmek için bir cronjob ekledim. Bu, kullanıcıların 90 günden daha eski değişiklikleri geri alabilecekleri anlamına gelir ve en az 90 günde bir senkronizasyon yaparlarsa, güncellemeler önceki gibi artırılır. Fakat 90 günden uzun beklerse,
Bu değişiklik, geçmiş tablosunun boyutunu neredeyse% 90 oranında azalttı, bu nedenle artık geçmiş tablosunu korumak, veritabanını on kat daha büyük değil, yalnızca iki kat büyütüyor. Bu sistemin bir başka avantajı da senkronizasyonun gerekirse geçmiş tablosu olmadan da çalışabilmesidir - geçici olarak çevrimdışı alan bazı bakımları yapmam gerekiyormuş gibi. Veya farklı fiyat noktalarındaki hesaplar için farklı geri alma süreleri sunabilirim. Ve indirilecek 90 günden fazla değişiklik varsa, tam dosya genellikle artımlı formattan daha verimlidir.
Bugün başlamış olsaydım, kimlik çakışması kontrolünü atlardım ve her ihtimale karşı bir tür hata kontrolü ile çatışmaları ortadan kaldırmak için yeterli bir anahtar uzunluğunu hedeflerdim. Ancak geçmiş tablosu ve son güncellemeler için artımlı indirmelerin veya gerektiğinde tam indirmenin kombinasyonu iyi çalışıyor.