Revizyonlar için Veritabanı Tasarımı?


125

Veritabanındaki varlıklar için tüm revizyonları (Değişiklik Geçmişi) kaydetme ihtiyacımız var. Şu anda bunun için 2 tasarlanmış teklifimiz var:

örneğin "Çalışan" Varlığı için

Tasarım 1:

-- Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

-- Holds the Employee Revisions in Xml. The RevisionXML will contain
-- all data of that particular EmployeeId
"EmployeeHistories (EmployeeId, DateModified, RevisionXML)"

Tasarım 2:

-- Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

-- In this approach we have basically duplicated all the fields on Employees 
-- in the EmployeeHistories and storing the revision data.
"EmployeeHistories (EmployeeId, RevisionId, DateModified, FirstName, 
      LastName, DepartmentId, .., ..)"

Bunu yapmanın başka bir yolu var mı?

"Tasarım 1" ile ilgili sorun, verilere her erişmeniz gerektiğinde XML'i ayrıştırmamız gerektiğidir. Bu, süreci yavaşlatacak ve revizyon veri alanlarına birleştirme ekleyemeyeceğimiz gibi bazı sınırlamalar da ekleyecektir.

Ve "Tasarım 2" ile ilgili sorun, tüm varlıklardaki her alanı çoğaltmamız gerektiğidir (revizyonlarını sürdürmek istediğimiz yaklaşık 70-80 varlığa sahibiz).



1
Bilginize: Her ihtimale karşı .Sql server 2008 ve üzeri, tablodaki değişikliklerin geçmişini gösteren bir teknolojiye sahiptir ... daha fazlasını öğrenmek için simple-talk.com/sql/learn-sql-server/… ziyaret edin ve eminim DB'ler Oracle gibi de böyle bir şeye sahip olacak.
Durai Amuthan. H

Bazı sütunların XML veya JSON'u kendilerinin saklayabileceğini unutmayın. Şimdi durum böyle değilse, gelecekte olabilir. Bu tür verileri iç içe yerleştirmenize gerek olmadığından emin olun.
jakubiszon

Yanıtlar:


38
  1. Do not bir IsCurrent ayırt edici özelliği olan bir tabloda tüm koydu. Bu sadece hattın aşağısında sorunlara neden olur, yedek anahtarlar ve her türlü başka sorun gerektirir.
  2. Tasarım 2'nin şema değişiklikleriyle ilgili sorunları var. Çalışanlar tablosunu değiştirirseniz, EmployeeHistories tablosunu ve onunla birlikte gelen tüm ilgili dişlileri de değiştirmeniz gerekir. Şema değiştirme çabanızı potansiyel olarak ikiye katlar.
  3. Tasarım 1 iyi çalışıyor ve doğru şekilde yapılırsa, bir performans vuruşu açısından çok pahalıya mal olmaz. Olası performans sorunlarını aşmak için bir xml şeması ve hatta dizinler kullanabilirsiniz. Xml'yi ayrıştırmakla ilgili yorumunuz geçerlidir, ancak xquery kullanarak kolayca bir görünüm oluşturabilirsiniz - bu, sorgulara ekleyebilir ve katılabilirsiniz. Bunun gibi bir şey ...
CREATE VIEW EmployeeHistory
AS
, FirstName, , DepartmentId

SELECT EmployeeId, RevisionXML.value('(/employee/FirstName)[1]', 'varchar(50)') AS FirstName,

  RevisionXML.value('(/employee/LastName)[1]', 'varchar(100)') AS LastName,

  RevisionXML.value('(/employee/DepartmentId)[1]', 'integer') AS DepartmentId,

FROM EmployeeHistories 

25
Neden IsCurrent tetikleyici ile hepsini tek bir tabloda saklamamayı söylüyorsunuz? Bunun sorunlu olacağı bazı örneklere işaret edebilir misiniz?
Nathan W

@Simon Munro Peki ya birincil anahtar veya kümelenmiş anahtar? Aramayı daha hızlı hale getirmek için Tasarım 1 geçmiş tablosuna hangi anahtarı ekleyebiliriz?
Gotqn

Tam bir tablo taramasında basit SELECT * FROM EmployeeHistory WHERE LastName = 'Doe'sonuçlar varsayıyorum . Bir uygulamayı ölçeklendirmek için en iyi fikir değil.
Kaii

54

Sanırım burada sorulacak anahtar soru 'Tarihi kim / ne kullanacak'?

Çoğunlukla raporlama / insan tarafından okunabilir tarih için olacaksa, bu şemayı geçmişte uyguladık ...

'AuditTrail' adlı bir tablo veya aşağıdaki alanlara sahip bir şey oluşturun ...

[ID] [int] IDENTITY(1,1) NOT NULL,
[UserID] [int] NULL,
[EventDate] [datetime] NOT NULL,
[TableName] [varchar](50) NOT NULL,
[RecordID] [varchar](20) NOT NULL,
[FieldName] [varchar](50) NULL,
[OldValue] [varchar](5000) NULL,
[NewValue] [varchar](5000) NULL

Daha sonra, tablo üzerinde her güncelleme / ekleme yaptığınızda ayarlanması gereken bir 'LastUpdatedByUserID' sütununu tüm tablolarınıza ekleyebilirsiniz.

Ardından, gerçekleşen herhangi bir ekleme / güncellemeyi yakalamak için her tabloya bir tetikleyici ekleyebilirsiniz ve bu tabloda değişen her alan için bir giriş oluşturur. Tablo ayrıca her güncelleme / ekleme için 'LastUpdateByUserID' ile sağlandığından, bu değere tetikleyicide erişebilir ve denetim tablosuna eklerken onu kullanabilirsiniz.

Güncellenmekte olan tablonun anahtar alanının değerini saklamak için RecordID alanını kullanıyoruz. Birleşik bir anahtar ise, alanlar arasında '~' ile bir dize birleştirme yaparız.

Eminim bu sistemin dezavantajları olabilir - yoğun şekilde güncellenen veritabanları için performans düşebilir, ancak web uygulamam için yazdıklardan çok daha fazla okuma alıyoruz ve oldukça iyi performans gösteriyor gibi görünüyor. Tetikleyicileri tablo tanımlarına göre otomatik olarak yazmak için küçük bir VB.NET aracı bile yazdık.

Sadece bir düşünce!


5
NewValue denetlenen tabloda saklandığı için saklamaya gerek yoktur.
Petrus Theron

17
Kesinlikle, bu doğru. Ancak - belirli bir süre içinde aynı alanda bir dizi değişiklik olduğunda, yeni değeri depolamak, 'Brian'ın yaptığı tüm değişiklikleri bana göster' gibi sorguları çok daha kolay hale getirir, çünkü bir güncelleme hakkındaki tüm bilgiler içeride tutulur bir kayıt. Sadece bir düşünce!
Chris Roberts

1
sysnameTablo ve sütun adları için daha uygun bir veri türü olabileceğini düşünüyorum .
Sam

2
@Sam, sysname kullanımı herhangi bir değer katmaz; kafa karıştırıcı bile olabilir ... stackoverflow.com/questions/5720212/…
Jowen

19

Tarih Tabloları makale Veritabanı Programcı blogunda yararlı olabilir - noktalardan bazılarını burada kaldırdı kapsar ve deltalar depolanmasını anlatılır.

Düzenle

Gelen Tarih Tablolar denemesinde, yazar ( Kenneth Downs ), en az yedi sütun bir geçmişi tablosuna koruyarak tavsiye eder:

  1. Değişimin zaman damgası,
  2. Değişikliği yapan kullanıcı,
  3. Değiştirilen kaydı tanımlamak için bir jeton (geçmişin mevcut durumdan ayrı tutulduğu yerde),
  4. Değişikliğin bir ekleme, güncelleme veya silme olup olmadığı,
  5. Eski değer,
  6. Yeni değer,
  7. Delta (sayısal değerlerde değişiklikler için).

Hiçbir zaman değişmeyen veya geçmişi gerekmeyen sütunlar, şişkinliği önlemek için geçmiş tablosunda izlenmemelidir. Deltanın sayısal değerler için depolanması, eski ve yeni değerlerden türetilebilse bile sonraki sorguları kolaylaştırabilir.

Geçmiş tablosu güvenli olmalı ve sistem dışı kullanıcıların satır eklemesi, güncellemesi veya silmesi engellenmelidir. Toplam boyutu küçültmek için yalnızca periyodik temizleme desteklenmelidir (ve kullanım durumu izin veriyorsa).


14

Chris Roberts'ın önerdiği çözüme çok benzer bir çözüm uyguladık ve bu bizim için oldukça iyi çalışıyor.

Tek fark, sadece yeni değeri saklamamızdır. Eski değer, önceki geçmiş satırında saklanır

[ID] [int] IDENTITY(1,1) NOT NULL,
[UserID] [int] NULL,
[EventDate] [datetime] NOT NULL,
[TableName] [varchar](50) NOT NULL,
[RecordID] [varchar](20) NOT NULL,
[FieldName] [varchar](50) NULL,
[NewValue] [varchar](5000) NULL

Diyelim ki 20 sütunlu bir tablonuz var. Bu şekilde, tüm satırı depolamak yerine yalnızca değişen sütunu tam olarak saklamanız gerekir.


14

Tasarımdan Kaçının 1; Örneğin, kayıtların eski sürümlerine geri dönmeniz gerektiğinde - otomatik olarak veya yönetici konsolunu kullanarak "manuel olarak" geri dönmeniz gerektiğinde çok kullanışlı değildir.

Tasarım 2'nin dezavantajlarını gerçekten görmüyorum. İkincisi, History tablosunun ilkinde, Kayıtlar tablosunda bulunan tüm sütunları içermesi gerektiğini düşünüyorum. Örneğin, mysql'de başka bir tabloyla ( create table X like Y) aynı yapıda kolayca tablo oluşturabilirsiniz . Ve canlı veritabanınızdaki Kayıtlar tablosunun yapısını değiştirmek üzereyken, alter tableyine de komutlar kullanmanız gerekir - ve bu komutları Geçmiş tablonuz için de çalıştırmak için çok fazla çaba sarf etmezsiniz.

notlar

  • Kayıtlar tablosu yalnızca en son düzeltmeyi içerir;
  • Geçmiş tablosu, Kayıtlar tablosundaki kayıtların önceki tüm revizyonlarını içerir;
  • Geçmiş tablosunun birincil anahtarı, RevisionIdsütun eklenmiş Kayıtlar tablosunun birincil anahtarıdır ;
  • ModifiedByBelirli bir revizyonu oluşturan kullanıcı gibi ek yardımcı alanları düşünün . Ayrıca, DeletedBybelirli bir revizyonu kimin sildiğini izlemek için bir alana sahip olmak isteyebilirsiniz .
  • Ne DateModifiedanlama geldiğini düşünün - ya bu belirli revizyonun nerede oluşturulduğu ya da bu belirli revizyonun başka bir revizyonla değiştirildiği anlamına gelir. İlki, alanın Kayıtlar tablosunda olmasını gerektirir ve ilk bakışta daha sezgisel görünür; ancak ikinci çözüm, silinen kayıtlar için daha pratik görünmektedir (bu özel revizyonun silindiği tarih). İlk çözüme giderseniz, muhtemelen ikinci bir alana DateDeletedihtiyacınız olacaktır (tabii ki buna ihtiyacınız varsa). Size ve gerçekte neyi kaydetmek istediğinize bağlıdır.

Tasarım 2'deki işlemler çok önemsizdir:

Değiştir
  • Kaydı Kayıtlar tablosundan Geçmiş tablosuna kopyalayın, yeni RevisionId verin (Kayıtlar tablosunda zaten mevcut değilse), DateModified'ı işleyin (nasıl yorumladığınıza bağlıdır, yukarıdaki notlara bakın)
  • Kayıtlar tablosundaki kaydın normal güncellemesine devam edin
Sil
  • Değiştirme işleminin ilk adımında olduğu gibi tam olarak aynı şeyi yapın. Seçtiğiniz yoruma bağlı olarak, DateModified / DateDeleted işleyin.
Silmeyi geri al (veya geri al)
  • Geçmiş tablosundan en yüksek (veya belirli bir?) revizyonu alın ve Kayıtlar tablosuna kopyalayın
Belirli bir kayıt için revizyon geçmişini listeleyin
  • Geçmiş tablosu ve Kayıtlar tablosundan seçin
  • bu operasyondan tam olarak ne beklediğinizi düşünün; Muhtemelen DateModified / DateDeleted alanlarından hangi bilgilere ihtiyacınız olduğunu belirleyecektir (yukarıdaki notlara bakın)

Tasarım 2'ye giderseniz, bunu yapmak için gereken tüm SQL komutlarının yanı sıra bakım da çok kolay olacaktır! Belki, her iki tabloyu da tamamen aynı yapıda tutmak için (benzersiz anahtarlar hariç ), Kayıtlar tablosunda da yardımcı sütunları ( RevisionId, DateModified) kullanırsanız çok daha kolay olacaktır ! Bu, herhangi bir veri yapısı değişikliğine tolerans gösterecek basit SQL komutlarına izin verecektir:

insert into EmployeeHistory select * from Employe where ID = XX

İşlemleri kullanmayı unutmayın!

Ölçeklendirmeye gelince , bu çözüm çok etkilidir, çünkü XML'den herhangi bir veriyi ileri geri dönüştürmüyorsunuz, sadece tüm tablo satırlarını kopyalıyorsunuz - çok basit sorgular, indisler kullanarak - çok verimli!


12

Geçmişi saklamanız gerekiyorsa, izlediğiniz tabloyla aynı şemaya ve bir 'Revizyon Tarihi' ve 'Revizyon Tipi' sütununa (ör. 'Sil', 'güncelleme') sahip bir gölge tablo oluşturun. Denetim tablosunu doldurmak için bir dizi tetikleyici yazın (veya oluşturun - aşağıya bakın).

Bir tablo için sistem veri sözlüğünü okuyacak ve gölge tablo ve onu doldurmak için bir dizi tetikleyici oluşturan bir komut dosyası oluşturacak bir araç yapmak oldukça basittir.

Bunun için XML kullanmaya çalışmayın, XML depolaması, bu tür tetikleyicinin kullandığı yerel veritabanı tablosu depolamasından çok daha az verimlidir.


3
Basitlik için +1! Bazıları daha sonraki değişikliklerden korktukları için aşırı mühendislik yaparken, çoğu zaman gerçekte hiçbir değişiklik olmaz! Ek olarak, bir tablodaki geçmişleri ve diğerindeki gerçek kayıtları yönetmek, hepsini bir bayrak veya durumla tek bir tabloda (kabus) bulundurmaktan çok daha kolaydır. Buna 'KISS' denir ve normalde sizi uzun vadede ödüllendirir.
Jeach

1 tamamen katılıyorum ben de dediklerimi Cevabıma ! Basit ve güçlü!
TMS

8

Ramesh, ilk yaklaşıma dayalı bir sistemin geliştirilmesine dahil oldum.
Revizyonları XML olarak depolamanın çok büyük bir veritabanı büyümesine yol açtığı ve işleri önemli ölçüde yavaşlattığı ortaya çıktı.
Yaklaşımım, varlık başına bir tabloya sahip olmak olacaktır:

Employee (Id, Name, ... , IsActive)  

nerede isActive son sürümü işaretidir

Bazı ek bilgileri revizyonlarla ilişkilendirmek isterseniz, bu bilgileri içeren ayrı bir tablo oluşturabilir ve PK \ FK ilişkisini kullanarak bunu varlık tablolarına bağlayabilirsiniz.

Bu şekilde çalışanların tüm versiyonlarını tek bir tabloda saklayabilirsiniz. Bu yaklaşımın artıları:

  • Basit veri tabanı yapısı
  • Tablo yalnızca sona eklendiğinden çakışma yok
  • Sadece IsActive bayrağını değiştirerek önceki sürüme geri dönebilirsiniz.
  • Nesne geçmişini almak için birleştirmeye gerek yok

Birincil anahtarın benzersiz olmamasına izin vermeniz gerektiğini unutmayın.


6
IsActive yerine veya ona ek olarak "RevisionNumber" veya "RevisionDate" sütununu kullanırdım, böylece tüm revizyonları sırayla görebilirsiniz.
Sklivvz

Bir "parentRowId" kullanırım çünkü bu size önceki sürümlere kolay erişim ve hem tabanı hem de sonunu hızlı bir şekilde bulma yeteneği sağlar.
chacham15

6

Bunun geçmişte yapıldığını görme şeklim var

Employees (EmployeeId, DateModified, < Employee Fields > , boolean isCurrent );

Bu tabloda asla "güncelleme" yapmazsınız (isCurrent'ın geçerliliğini değiştirmek dışında), sadece yeni satırlar ekleyin. Herhangi bir EmployeeId için yalnızca 1 satırda isCurrent == 1 olabilir.

Bunu sürdürmenin karmaşıklığı, görünümler ve "tetikleyiciler" yerine gizlenebilir (oracle'da benzer şeyleri diğer RDBMS'lerde varsayıyorum), tablolar çok büyükse ve dizinler tarafından ele alınamıyorsa, somut görünümlere bile gidebilirsiniz) .

Bu yöntem tamam, ancak bazı karmaşık sorgularla sonuçlanabilirsiniz.

Kişisel olarak, Tasarım 2'nin bunu yapma şeklini çok seviyorum, geçmişte de bunu böyle yaptım. Anlaşılması basit, uygulaması basit ve bakımı basit.

Ayrıca, özellikle okuma sorguları gerçekleştirirken, veritabanı ve uygulama için çok az ek yük yaratır, ki bu muhtemelen zamanın% 99'unda yapacağınız şeydir.

Geçmiş tablolarının ve tetikleyicilerin oluşturulmasının otomatik olarak oluşturulması da oldukça kolay olacaktır (bunun tetikleyiciler aracılığıyla yapılacağını varsayarsak).


4

Verilerin revizyonları, Temporal Veritabanının ' geçerli zaman ' kavramının bir yönüdür . Bu konuyla ilgili pek çok araştırma yapıldı ve birçok kalıp ve kılavuz ortaya çıktı. İlgilenenler için bu soruya bir dizi referans içeren uzun bir cevap yazdım .


4

Sizinle tasarımımı paylaşacağım ve her bir varlık türü için bir tablo gerektirmesi bakımından her iki tasarımınızdan farklıdır. Herhangi bir veritabanı tasarımını tanımlamanın en iyi yolunu buldum, işte benimki: ERD:

görüntü açıklamasını buraya girin

Bu örnekte çalışan adında bir varlığımız var . kullanıcı tablosu, kullanıcılarınızın kayıtlarını tutar ve varlık ve varlık_görünümü , sisteminizde sahip olacağınız tüm varlık türleri için revizyon geçmişini tutan iki tablodur . Bu tasarım şu şekilde çalışır:

Entity_id ve revision_id için iki alan

Sisteminizdeki her varlığın kendine ait benzersiz bir varlık kimliği olacaktır. Varlığınız revizyonlardan geçebilir ancak varlık kimliği aynı kalacaktır. Bu varlık kimliğini çalışan tablonuzda (yabancı anahtar olarak) tutmanız gerekir. Varlığınızın türünü de varlık tablosunda saklamalısınız (örneğin, 'çalışan'). Revision_id'ye gelince, adından da anlaşılacağı gibi, varlık revizyonlarınızı takip eder. Bunun için bulunan en iyi yolu kullanmaktır employee_id sizin REVISION_ID olarak. Bu, farklı türdeki varlıklar için yinelenen revizyon kimliklerine sahip olacağınız anlamına gelir, ancak bu benim için bir muamele değildir (durumunuzdan emin değilim). Yapılması gereken tek önemli not, entity_id ve revision_id kombinasyonunun benzersiz olması gerektiğidir.

Ayrıca bir Entity_revision tablosunda revizyon durumunu gösteren durum alanı . Bu üç durumdan birine sahip olabilir: latest, obsoleteveya deleted(revizyon tarihindeki güvenerek değil size sorguları artırmak için bir hayli yardımcı olur).

Revision_id ile ilgili son bir not: Employ_id ile revision_id arasında bağlantı kuran bir yabancı anahtar oluşturmadım, çünkü gelecekte ekleyebileceğimiz her varlık türü için entity_revision tablosunu değiştirmek istemiyoruz.

EKLEME

Veritabanına eklemek istediğiniz her çalışan için ayrıca bir kayıt da ekleyeceksiniz. varlık ve varlık_görünümüne . Bu son iki kayıt, veritabanına bir kaydın kim tarafından ve ne zaman eklendiğini izlemenize yardımcı olacaktır.

GÜNCELLEME

Mevcut bir çalışan kaydı için her güncelleme, biri çalışan tablosunda, diğeri varlık_başvurusunda olmak üzere iki ek olarak uygulanacaktır. İkincisi, kaydın kim tarafından ve ne zaman güncellendiğini bilmenize yardımcı olacaktır.

SİLME

Bir çalışanı silmek için, entity_revision içine silme işlemini belirten bir kayıt eklenir ve yapılır.

Bu tasarımda görebileceğiniz gibi, veri tabanından hiçbir veri değiştirilmez veya kaldırılmaz ve daha da önemlisi her varlık türü yalnızca bir tablo gerektirir. Şahsen ben bu tasarımı gerçekten esnek ve kullanımı kolay buluyorum. Ama ihtiyaçlarınız farklı olabileceğinden emin değilim.

[GÜNCELLEME]

Yeni MySQL sürümlerinde desteklenen bölümleri olduğu için tasarımımın da en iyi performanslardan biriyle geldiğine inanıyorum. Bir bölümlemek entitykullanarak tablo typebölüm ise alanını entity_revisionkendi kullanarak statealanını. Bu SELECT, tasarımı basit ve temiz tutarken sorguları büyük ölçüde artıracaktır .


3

Gerçekten ihtiyacınız olan tek şey bir denetim izi ise, denetim tablosu çözümüne yönelirim (diğer tablolardaki önemli sütunun normal olmayan kopyalarıyla birlikte, örn. UserName ). Bununla birlikte, bu acı deneyimin, tek bir denetim tablosunun yolda büyük bir darboğaz olacağını gösterdiğini unutmayın; Muhtemelen tüm denetlenen tablolarınız için ayrı denetim tabloları oluşturma çabasına değer.

Gerçek geçmiş (ve / veya gelecekteki) sürümleri izlemeniz gerekiyorsa, standart çözüm, aynı varlığı birden çok satırla, başlangıç, bitiş ve süre değerlerinin bazı kombinasyonlarını kullanarak izlemektir. Mevcut değerlere erişimi kolaylaştırmak için bir görünüm kullanabilirsiniz. Kullandığınız yaklaşım buysa, sürümlü verileriniz değiştirilebilir ancak dönüştürülmemiş verilere başvuruyorsa sorunlarla karşılaşabilirsiniz.


3

İlkini yapmak istiyorsanız, Çalışanlar tablosu için de XML kullanmak isteyebilirsiniz. Çoğu yeni veritabanı, XML alanlarını sorgulamanıza izin verir, bu nedenle bu her zaman bir sorun değildir. Ayrıca, en son sürüm veya daha eski bir sürüm olup olmadığına bakılmaksızın, çalışan verilerine erişmenin tek bir yolunun olması daha kolay olabilir.

Yine de ikinci yaklaşımı deneyecektim. Bunu, DateModified alanı olan tek bir Çalışanlar tablosuna sahip olarak basitleştirebilirsiniz. EmployeeId + DateModified, birincil anahtar olacaktır ve yalnızca bir satır ekleyerek yeni bir revizyonu depolayabilirsiniz. Bu şekilde eski sürümleri arşivlemek ve sürümleri arşivden geri yüklemek de daha kolaydır.

Bunu yapmanın bir başka yolu da Dan Linstedt'in veri değerlendirme modeli olabilir . Hollanda istatistik bürosu için bu modeli kullanan bir proje yaptım ve oldukça iyi çalışıyor. Ancak günlük veritabanı kullanımı için doğrudan yararlı olduğunu düşünmüyorum. Yine de onun kağıtlarını okurken bazı fikirler edinebilirsiniz.


2

Peki ya:

  • Çalışan kimliği
  • Değiştirilme tarihi
    • ve / veya revizyon numarası, onu nasıl izlemek istediğinize bağlı olarak
  • ModifiedByUSerId
    • artı izlemek istediğiniz diğer bilgiler
  • Çalışan alanları

Birincil anahtarı (EmployeeId, DateModified) yaparsınız ve "geçerli" kayıtları almak için her bir çalışan kimliği için MAX (DateModified) öğesini seçmeniz yeterlidir. Bir IsCurrent'ı saklamak çok kötü bir fikirdir, çünkü her şeyden önce hesaplanabilir ve ikincisi, verilerin senkronizasyondan çıkması çok kolaydır.

Ayrıca, yalnızca en son kayıtları listeleyen bir görünüm oluşturabilir ve bunu çoğunlukla uygulamanızda çalışırken kullanabilirsiniz. Bu yaklaşımın güzel yanı, verilerin kopyalarına sahip olmamanız ve tüm geçmişi veya geri alma, vb. Almak için iki farklı yerden (Çalışanlar'da geçerli ve EmployeesHistory'de arşivlenmiş) veri toplamanız gerekmemesidir. .


Bu yaklaşımın bir dezavantajı, tablonun iki tablo kullandığınıza göre daha hızlı büyümesidir.
cdmckay

2

Geçmiş verilerine güvenmek istiyorsanız (raporlama nedenleriyle) şuna benzer bir yapı kullanmalısınız:

// Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

// Holds the Employee revisions in rows.
"EmployeeHistories (HistoryId, EmployeeId, DateModified, OldValue, NewValue, FieldName)"

Veya uygulama için küresel çözüm:

// Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

// Holds all entities revisions in rows.
"EntityChanges (EntityName, EntityId, DateModified, OldValue, NewValue, FieldName)"

Revizyonlarınızı XML olarak da kaydedebilirsiniz, ardından bir revizyon için yalnızca bir kaydınız olur. Bu şöyle görünecek:

// Holds Employee Entity
"Employees (EmployeeId, FirstName, LastName, DepartmentId, .., ..)"

// Holds all entities revisions in rows.
"EntityChanges (EntityName, EntityId, DateModified, XMLChanges)"

1
Daha iyi: Kullanım olay kaynak :)
dariol

1

Benzer gereksinimlerimiz vardı ve bulduğumuz şey, çoğu zaman kullanıcının yalnızca neyin değiştiğini görmek istediği, herhangi bir değişikliği geri almak istemediğiydi.

Kullanım durumunuzdan emin değilim, ancak yaptığımız şey, herhangi bir yabancı anahtar referansının ve numaralandırmasının kolay adı da dahil olmak üzere bir işletme varlığındaki değişikliklerle otomatik olarak güncellenen Denetim tablosu oluşturmak ve denetlemek oldu.

Kullanıcı değişikliklerini kaydettiğinde eski nesneyi yeniden yükleriz, bir karşılaştırma yaparız, değişiklikleri kaydederiz ve varlığı kaydederiz (herhangi bir sorun olması durumunda tümü tek bir veritabanı işleminde yapılır).

Bu, kullanıcılarımız için çok iyi çalışıyor gibi görünüyor ve bizi ticari varlığımızla aynı alanlara sahip tamamen ayrı bir denetim tablosuna sahip olmanın baş ağrısından kurtarıyor.


0

Zaman içinde belirli varlıklarda meydana gelen değişiklikleri izlemek istiyormuşsunuz gibi geliyor, örneğin ID 3, "bob", "123 main street", ardından başka bir ID 3, "bob" "234 elm st", vb. "bob" un bulunduğu her adresi gösteren bir revizyon geçmişini kusmak için.

Bunu yapmanın en iyi yolu, her kayıtta bir "güncel" alanı ve (muhtemelen) bir zaman damgası veya bir tarih / saat tablosu için FK bulundurmaktır.

Eklemelerin daha sonra "güncel" ayarını yapması ve ayrıca önceki "güncel" kaydındaki "güncel" ayarını kaldırması gerekir. Geçmişin tamamını istemediğiniz sürece sorgular "günceldir" olarak belirtilmelidir.

Çok büyük bir tabloysa veya çok sayıda revizyon bekleniyorsa, bu konuda başka ince ayarlar da vardır, ancak bu oldukça standart bir yaklaşımdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.