Geçmiş Verileri Nasıl Saklanır?


162

Bazı iş arkadaşları ve ben tarihsel verileri depolamanın en iyi yolu hakkında bir tartışmaya girdik. Şu anda, bazı sistemler için geçmiş verilerini depolamak için ayrı bir tablo kullanıyorum ve geçerli, aktif kayıt için orijinal bir tablo tutuyorum. Diyelim ki FOO masam var. Sistemim altında, tüm etkin kayıtlar FOO'ya ve tüm geçmiş kayıtlar FOO_Hist'e gidecek. FOO'daki birçok farklı alan kullanıcı tarafından güncellenebilir, bu yüzden her şeyin güncelliğini doğru bir şekilde tutmak istiyorum. FOO_Hist, otomatik artan HIST_ID haricinde FOO ile tam olarak aynı alanları tutar. FOO her güncellendiğinde, FOO_Hist'e aşağıdakine benzer bir ekleme ifadesi gerçekleştiririm insert into FOO_HIST select * from FOO where id = @id.

İş arkadaşım bunun kötü bir tasarım olduğunu söylüyor çünkü tarihsel nedenlerden ötürü bir tablonun tam bir kopyasına sahip olmamalıyım ve aktif tabloya sadece tarihi amaçlar için olduğunu belirten bir bayrakla başka bir kayıt eklemeliyim.

Geçmiş veri depolama ile ilgili bir standart var mı? Bana öyle geliyor ki, aktif kayıtlarımı bir milyondan fazla kayıt olabileceğini düşünerek aynı tablodaki tüm tarihsel kayıtlarım ile karıştırmak istemiyorum (uzun vadeli düşünüyorum).

Siz veya şirketiniz bunu nasıl hallediyorsunuz?

MS SQL Server 2008 kullanıyorum, ancak yanıtı genel ve keyfi herhangi bir DBMS tutmak istiyorum.

Yanıtlar:


80

Geçmiş verilerin doğrudan bir işletim sistemi içinde desteklenmesi, uygulamanızı diğerlerinden daha karmaşık hale getirecektir. Genel olarak, sistemdeki bir kaydın tarihsel sürümlerini değiştirmek için zor bir gereksiniminiz yoksa bunu yapmanızı önermem.

Yakından bakarsanız, geçmiş veriler için gereksinimlerin çoğu iki kategoriden birine girer:

  • Denetim günlüğü: Bu, denetim tablolarıyla daha iyi yapılır. Sistem veri sözlüğünden meta verileri okuyarak denetim günlüğü tabloları ve tetikleyiciler oluşturmak için komut dosyaları üreten bir araç yazmak oldukça kolaydır. Bu tür araç, denetim günlüğünü çoğu sisteme uyarlamak için kullanılabilir. Bir veri ambarı uygulamak istiyorsanız bu alt sistemi değiştirilmiş veri yakalama için de kullanabilirsiniz (aşağıya bakın).

  • Tarihsel raporlama: Tarihsel durum, 'olduğu gibi' konumlar veya zaman içinde analitik raporlama hakkında raporlama. Yukarıda açıklanan türden denetim günlüğü tablolarını sorgulayarak basit geçmiş raporlama gereksinimlerini karşılamak mümkün olabilir. Daha karmaşık gereksinimleriniz varsa, raporlama için bir veri martını uygulamak, geçmişi doğrudan işletim sistemine entegre etmeye çalışmaktan daha ekonomik olabilir.

    Yavaş değişen boyutlar, geçmiş durumu izlemek ve sorgulamak için açık ara en basit mekanizmadır ve geçmiş izlemenin çoğu otomatikleştirilebilir. Genel işleyiciler yazmak o kadar da zor değildir. Genel olarak, geçmiş raporların en güncel verileri kullanması gerekmez, bu nedenle toplu bir yenileme mekanizması normal olarak iyidir. Bu, çekirdek ve raporlama sistem mimarinizi nispeten basit tutar.

Gereksinimleriniz bu iki kategoriden birine girerse, muhtemelen geçmiş verilerinizi işletim sisteminizde depolamamanız daha iyi olur. Tarihsel işlevselliği başka bir alt sisteme ayırmak muhtemelen daha az çaba harcayacak ve amaçlanan amaçları için daha iyi çalışan işlem ve denetim / raporlama veritabanları üretecektir.


Sanırım ne dediğini anlıyorum. Bu yüzden FOO_Hist tablomla yaptığım şey gerçekten bir denetim tablosu oluşturmaktı. Güncellemedeki denetim tablosuna eklemek için bir tetikleyici kullanmak yerine, programda bir açıklama çalıştırdım. Bu doğru mu?
Aaron

6
Neredeyse. Bununla birlikte, bu tür denetim günlüğünü tetikleyicilerle yapmak daha iyidir; tetikleyiciler, değişikliklerin (manuel veri düzeltmeleri dahil) denetim günlüklerine kaydedilmesini sağlar. Denetlemek için 10-20'den fazla tablonuz varsa, bir tetikleyici oluşturma aracı oluşturmak muhtemelen hepsinden daha hızlıdır. Denetim günlükleri için disk trafiği bir sorunsa, denetim günlüğü tablolarını ayrı bir disk grubuna koyabilirsiniz.
ConcernedOfTunbridgeWells

Evet, buna% 100 katılıyorum. Teşekkür ederim.
Aaron

40

Bunu yapmanın standart bir yolu olduğunu düşünmüyorum ama olası bir yöntemle atacağımı düşündüm. Oracle ve uygulama verilerini depolamak için XML kullanan şirket içi web uygulama çerçevemizde çalışıyorum.

En basitinden oluşan Master - Detay modeli olarak adlandırılan bir şey kullanıyoruz:

Örneğin Ana Tablo , Widgetsgenellikle sadece bir kimlik içeren olarak adlandırılır . Genellikle zaman içinde değişmeyecek / geçmişte olmayan veriler içerir.

Ayrıntı / Geçmiş Tablosu , örneğin Widget_Detailsen az içeren:

  • Kimlik - birincil anahtar. Ayrıntı / geçmiş kimliği
  • MASTER_ID - örneğin 'WIDGET_ID' olarak adlandırılan bu durumda, bu Ana kaydın FK'si
  • START_DATETIME - bu veritabanı satırının başlangıcını gösteren zaman damgası
  • END_DATETIME - bu veritabanı satırının sonunu gösteren zaman damgası
  • STATUS_CONTROL - tek karakterlik sütun satırın durumunu gösterir. 'C', geçerli, NULL veya 'A' nın geçmiş / arşivlenmiş olacağını belirtir. Bunu sadece END_DATETIME NULL olacak şekilde dizine ekleyemediğimiz için kullanıyoruz
  • CREATED_BY_WUA_ID - satırın oluşturulmasına neden olan hesabın kimliğini depolar
  • XMLDATA - gerçek verileri saklar

Bu nedenle, esas olarak, varlık master'da 1 satır ve detayda 1 satır olmasıyla başlar. NULL bitiş tarihi ve STATUS_CONTROL değeri 'C' olan ayrıntı. Bir güncelleme gerçekleştiğinde, geçerli satır END_DATETIME geçerli zamana sahip olacak şekilde güncellenir ve status_control NULL (veya tercih edilirse 'A') olarak ayarlanır. Ayrıntı tablosunda, hala aynı master'a bağlı olan status_control 'C', güncellemeyi yapan kişinin kimliği ve XMLDATA sütununda depolanan yeni veriler ile yeni bir satır oluşturulur.

Tarihsel modelimizin temeli budur. Oluştur / Güncelle mantığı bir Oracle PL / SQL paketinde işlenir, böylece sadece geçerli kimliği, kullanıcı kimliğinizi ve yeni XML verilerini işleve geçirirsiniz ve dahili olarak geçmiş modelde bunu temsil etmek için tüm satırları günceller / ekler . Başlangıç ​​ve bitiş saatleri, tablodaki bu satırın ne zaman etkin olduğunu gösterir.

Depolama ucuzdur, genellikle verileri SİLMEZ ve bir denetim izi tutmayı tercih ederiz. Bu, verilerimizin herhangi bir zamanda neye benzediğini görmemizi sağlar. Status_control = 'C' indeksleyerek veya bir Görünüm kullanarak, dağınıklık tam olarak bir sorun oluşturmaz. Açıkçası, sorgularınızın her zaman bir kaydın geçerli (NULL end_datetime ve status_control = 'C') sürümünü kullanmanız gerektiğini dikkate alması gerekir.


Merhaba Chris, bunu yaparsanız, kimlik (birincil anahtar) değişmeli mi? başka bir tablo ile ilişkiliyse başka bir tablo ile ilişkisine ne dersiniz?
projo

@projo ana masanızdaki kimlik PK ve kavramsal olarak uğraştığınız kavram için "PK" dır. Ayrıntı tablosundaki kimlik, ana öğenin (ayrıntıdaki başka bir sütundur) geçmiş bir sürümünü tanımlayan PK'dır. İlişkiler oluştururken genellikle konseptinizin gerçek PK'sine (yani ana tablonuzdaki kimlik veya ayrıntılarınızdaki MASTER_ID sütunu) referans verir ve geçerli sürümü aldığınızdan emin olmak için STATUS_CONTROL = 'C' kullanırsınız. Alternatif olarak, belirli bir noktadaki bir şeyi ilişkilendirmek için ayrıntı kimliğine başvurabilirsiniz.
Chris Cameron-Mills

+1 Bu modeli birkaç büyük projede büyük bir başarıyla uyguladım.
Üç Değerli Mantık

Aynı yaklaşımı kullanıyoruz. Ama şimdi merak ediyorum sadece START_DATETIME saklamak ve saklamamak daha iyidir END_DATETIME
bat_ventzi

Deneyimlerimde birkaç varyasyon. Varlığınız "sona erdiyse", yani arşivlendiğinde veya silindiğinde, gerçekte 'C' durum kontrolüne sahip ayrıntılı bir kayda sahip olamazsınız, yani mevcut satırınız olmaz, ancak bunun ne zaman olduğunu bilmezsiniz. Alternatif olarak, son satırda bir end_datetime ayarlayabilirsiniz ve 'bitişli' 'C' satırının bulunması, varlığın artık silindiğini / arşivlendiğini gösterebilir. Son olarak, bunu zaten sahip olabileceğiniz başka bir STATUS sütunundan gösterebilirsiniz.
Chris Cameron-Mills

15

Bence yaklaşım doğru. Geçmiş tablosu, ana tablonun dizinsiz bir kopyası olmalıdır, tabloda güncelleme zaman damgasına da sahip olduğunuzdan emin olun.

Diğer yaklaşımı yeterince denerseniz sorun yaşarsınız:

  • bakım yükü
  • seçimlerde daha fazla bayrak
  • yavaşlama sorguları
  • tablo, indeks büyümesi

7

Gelen SQL Server 2016 ve üstü olarak adlandırılan yeni bir özellik vardır Geçici Tablolar amaçları ile bu sorunu çözmeye o geliştiriciden az çaba . Geçici tablo kavramı, Veri Yakalamayı Değiştir'e (CDC) benzer, geçici tablo CDC kullanıyorsanız manuel olarak yapmanız gerekenlerin çoğunu soyutlamıştır.




1

Sadece Azure SQL kullandığım ve çoklu tablo şey benim için çok hantal çünkü kullanmaya başladığım bir seçenek eklemek istedim. Masamda bir ekleme / güncelleme / silme tetikleyicisi ekledikten sonra "JSON OTOMATİK FORMU" özelliğini kullanarak önceki / sonraki değişikliği json'a dönüştürdüm.

 SET @beforeJson = (SELECT * FROM DELETED FOR JSON AUTO)
SET @afterJson = (SELECT * FROM INSERTED FOR JSON AUTO)

Bu değişiklikten önce / sonra kayıt için bir JSON temsili döndürür. Daha sonra bu değerleri bir tarih tablosunda değişikliğin ne zaman gerçekleştiğine dair bir zaman damgasıyla saklıyorum (ayrıca geçerli kaygı kaydının kimliğini de saklıyorum). Serileştirme işlemini kullanarak, şemada değişiklik olması durumunda verilerin nasıl doldurulacağını kontrol edebilirim.

Bunu buradaki bağlantıdan öğrendim


0

Sadece tabloları bölümlere ayırabilir misin?

"SQL Server 2008 Kullanan Bölümlenmiş Tablo ve Dizin Stratejileri Bir veritabanı tablosunun boyutu yüzlerce gigabayt veya daha fazla bir boyuta büyüdüğünde, yeni verileri yüklemek, eski verileri kaldırmak ve dizinleri korumak daha zor hale gelebilir. Yüklenmesi veya kaldırılması gereken veriler bile çok büyük olabilir, bu da tablodaki INSERT ve DELETE işlemlerini uygulanamaz hale getirir. Microsoft SQL Server 2008 veritabanı yazılımı, bu tür işlemleri daha yönetilebilir hale getirmek için tablo bölümleme sağlar. "


Evet, tabloları bölümlere ayırabilirim, ancak geçmiş verilerle uğraşırken standart bu mu? Geçmiş veriler etkin verilerle aynı tabloya eklenmeli mi? Bunlar tartışmak istediğim sorular. Bu aynı zamanda SQL Server 2008 ile ilgili olduğu için keyfi değildir.
Aaron

0

Asıl soru, raporlama için geçmiş verileri ve aktif verileri birlikte kullanmanız mı gerekiyor? Öyleyse, bunları tek bir tabloda tutun, etkin sorgularda etkin sorgularda kullanmak için bölüm oluşturun ve bir görünüm oluşturun. Onlara sadece ara sıra bakmanız gerekiyorsa (leagal meselelerini veya bazılarını araştırmak için) ayrı bir tabloya koyun.


2
JOINBirkaç geçmiş raporda iki tablo oluşturmak daha mı zor, yoksa her bir tablo ekleme / güncelleme / silme işleminin tarihsel kaygıların farkında olması için değiştirilmesi daha mı zor? Aslında, bir denetim günlüğü geçmiş tablosundaki geçerli verileri bile içerecektir, bu nedenle raporda geçerli tabloya bile gerek yoktur.

0

Başka bir seçenek de operasyonel verileri [günlük | saatlik | her neyse] temelinde arşivlemektir. Çoğu veritabanı motoru , verilerin bir arşive alınmasını destekler .

Temel olarak, planlanan bir Windows veya CRON işi oluşturmak

  1. operasyonel veritabanındaki mevcut tabloları belirler
  2. her tablodaki tüm verileri bir CSV veya XML dosyasına seçer
  3. dışa aktarılan verileri, daha kolay arşivleme için tercihen dosya adındaki neslin zaman damgası ile birlikte bir ZIP dosyasına sıkıştırır.

Birçok SQL veritabanı motoru, bu amaçla kullanılabilecek bir araçla birlikte gelir. Örneğin, Linux'ta MySQL kullanırken, ayıklamayı zamanlamak için bir CRON işinde aşağıdaki komut kullanılabilir:

mysqldump --all-databases --xml --lock-tables=false -ppassword | gzip -c | cat > /media/bak/servername-$(date +%Y-%m-%d)-mysql.xml.gz

2
Bu, geçmiş veriler için hiç uygun değildir, çünkü biri değeri değiştirip arşiv döngüsü içinde değiştirirse, güncellemeler kaybolur. Ayrıca, zaman içinde bir varlıktaki değişikliklere bakmanın veya bir varlığı kısmen geri yüklemenin kolay bir yolu yoktur.
Sgoettschkes

0

Bu eski gönderiyi biliyorum ama Sadece birkaç puan eklemek istedim. Bu tür problemler için standart, durum için en iyi olan şeydir. bu tür bir depolama ihtiyacını ve geçmiş / denetim / değişiklik izleme verilerinin potansiyel kullanımını anlamak çok önemlidir.

Denetim (güvenlik amacı) : Tüm denetlenebilir tablolarınız için ortak bir tablo kullanın. değerden önce ve sonra değer alanlarının sütun adını depolayacak yapıyı tanımlar.

Arşiv / Geçmiş : önceki adresi izleme, telefon numarası vb. Gibi ayrı bir tablo oluşturmak için etkin işlem tablosu şemanız gelecekte önemli ölçüde değişmezse (geçmiş tablonuzun aynı yapıya sahip olması gerekiyorsa) FOO_HIST daha iyidir. tablonun normalleştirilmesini, sütunların eklenmesini / kaldırılmasını veri türünü değiştirmeyi düşünüyorsanız, geçmiş verilerinizi xml biçiminde depolayın. Aşağıdaki sütunları içeren bir tablo tanımlayın (ID, Tarih, Şema Sürümü, XMLData). bu, şema değişikliklerini kolayca halledecektir. ancak xml ile uğraşmak zorundasınız ve bu veri almak için bir miktar zorluk getirebilir.



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.