Praktik terbaik untuk tabel sejarah / temporal?

11

Misalkan saya memiliki objek, dengan bidang tertentu yang ingin saya lacak sejarah, dan bidang tertentu yang saya tidak ingin melacak sejarah. Dari perspektif normalisasi, apakah skema berikut baik-baik saja:

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)

di mana MyObjectHistory berisi bidang yang dilacak untuk semua kecuali untuk revisi terbaru. Atau, jika semua bidang yang dilacak berada dalam satu tabel, dan semua revisi termasuk yang terbaru di tabel itu, seperti pada:

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)
cubetwo1729
sumber
Saya setuju dengan @ Joel
HaBo

Jawaban:

7

Untuk alasan akses data praktis, Anda harus menggunakan struktur dari opsi pertama Anda, tetapi tetap menyimpan semua versi dari nilai kolom yang dilacak termasuk versi saat ini di tabel riwayat Anda.

Alasan untuk ini adalah bahwa secara umum, ketika Anda ingin melihat sejarah, Anda ingin menyertakan versi sekarang dan semua versi sebelumnya. Ketika Anda tidak ingin melihat sejarah, Anda menginginkannya. Dalam banyak kasus ini berarti melangkah jauh untuk memisahkan sejarah menjadi skema atau basis data yang terpisah sama sekali. Bahkan jika Anda menyimpan riwayat Anda dalam skema yang sama dengan data Anda saat ini, setiap pertanyaan yang melihat data historis (termasuk nilai saat ini) akan jauh lebih kompleks karena mereka pada dasarnya harus menyatukan dua sumber.

Joel Brown
sumber
2

Saya lebih suka versi pertama karena Anda mungkin jarang perlu melihat histori tetapi Anda sering perlu melihat nilai saat ini. Tabel riwayat harus diisi dari pemicu, jadi Anda tidak perlu khawatir tentang data yang keluar dari sinkronisasi umumnya. Jadi misalkan Anda memiliki sejuta catatan di MyObject dan kemudian Anda memiliki 10.000.000 catatan di MyObjectHistory. Apakah Anda benar-benar ingin bergabung ke tabel dengan banyak catatan untuk mendapatkan nilai saat ini?

Sekarang jika Anda akan perlu kueri sejarah dengan frekuensi yang sering atau lebih sering daripada nilai saat ini, maka struture kedua akan bekerja. (Dan jika Anda akan menampilkan nilai pada tanggal tertentu, saya akan memiliki bidang begindate dan enddate di dalamnya untuk membuat kueri lebih sederhana.)

BTW Saya akan menambahkan bidang tanggal ke tabel sejarah untuk dapat mengetahui urutan perubahan yang terjadi. Anda tidak dapat mengandalkan identitas untuk tatanan sementara. Karena jika ada pertanyaan tentang nilai previosu dan ketika itu berubah, Anda perlu tahu. Saya mungkin juga memasukkan nilai untuk aplikasi yang perubahannya berasal (jika Anda memiliki beberapa aplikasi) dan / atau orang yang melakukan perubahan.

HLGEM
sumber
0

Ada beberapa alasan penting untuk # 1. Yang pertama adalah masalah ukuran yang ditunjukkan HLGEM tetapi ada juga yang penting.

Biasanya jejak audit Anda akan memiliki persyaratan berkembang dari waktu ke waktu. Anda mungkin ingin melacak pengguna basis data, waktu perubahan, dll. Persyaratan jejak audit dan tabel utama Anda cenderung berubah seiring waktu secara independen. Akhirnya Anda mungkin ingin membersihkan data jejak audit setelah periode waktu yang terpisah dan tabel yang sepenuhnya terpisah.

Tentu saja mungkin ada kasus di mana Anda ingin sepenuhnya menggabungkan mereka (seperti yang kami lakukan untuk tarif pajak di LedgerSMB) karena data historis dapat digunakan untuk perhitungan saat ini dan jumlah catatan cenderung relatif kecil.

Saya akan menyarankan, bagaimanapun, bahwa menyimpan objek dalam tabel seperti ini jarang mengarah pada desain yang baik dan normal. Dalam pengalaman saya, Anda benar-benar ingin enkapsulasi antara penyimpanan dinormalisasi yang baik dan model objek aplikasi.

Chris Travers
sumber
2
Apa yang Anda maksud dengan “enkapsulasi antara penyimpanan dinormalisasi yang baik dan model objek aplikasi”? Apakah Anda akan menguraikan ide ini atau memberi contoh?
cubetwo1729