Secara efisien menyimpan set pasangan nilai kunci dengan kunci yang sangat berbeda

9

Saya mewarisi aplikasi yang mengaitkan berbagai jenis kegiatan dengan situs. Ada sekitar 100 jenis aktivitas yang berbeda, dan masing-masing memiliki set bidang yang berbeda 3-10. Namun, semua aktivitas memiliki setidaknya satu bidang tanggal (bisa berupa kombinasi tanggal, tanggal mulai, tanggal akhir, tanggal mulai yang dijadwalkan, dll.), Dan satu bidang orang yang bertanggung jawab. Semua bidang lainnya sangat bervariasi dan bidang tanggal mulai tidak harus disebut "Tanggal Mulai".

Membuat satu tabel subtipe untuk setiap jenis aktivitas akan menghasilkan skema dengan 100 tabel subtipe berbeda, yang akan terlalu sulit untuk dihadapi. Solusi saat ini untuk masalah ini adalah untuk menyimpan nilai aktivitas sebagai pasangan nilai kunci. Ini adalah skema yang sangat disederhanakan dari sistem saat ini untuk menyampaikan maksudnya.

masukkan deskripsi gambar di sini

Setiap Kegiatan memiliki beberapa ActivityFields; setiap Situs memiliki beberapa Kegiatan, dan tabel SiteActivityData menyimpan KVP untuk setiap SiteActivity.

Ini membuat aplikasi (berbasis web) sangat mudah untuk dikodekan karena yang perlu Anda lakukan hanyalah mengulang catatan di SiteActivityData untuk aktivitas tertentu dan menambahkan label dan kontrol input untuk setiap baris ke formulir. Tetapi ada banyak masalah:

  • Integritas buruk; dimungkinkan untuk meletakkan bidang di SiteActivityData yang bukan milik tipe aktivitas, dan DataValue adalah bidang varchar sehingga angka dan tanggal harus terus-menerus dilemparkan.
  • Pelaporan dan permintaan ad-hoc data ini sulit, rawan kesalahan, dan lambat. Misalnya, mendapatkan daftar semua aktivitas dari jenis tertentu yang memiliki Tanggal Berakhir dalam rentang yang ditentukan membutuhkan pivot dan casting varchars ke tanggal. Penulis laporan BENCI skema ini, dan saya tidak menyalahkan mereka.

Jadi yang saya cari adalah cara untuk menyimpan sejumlah besar kegiatan yang hampir tidak memiliki bidang yang sama sehingga membuat pelaporan menjadi lebih mudah. Sejauh ini yang saya pikirkan adalah menggunakan XML untuk menyimpan data aktivitas dalam format pseudo-noSQL:

masukkan deskripsi gambar di sini

Tabel Aktivitas akan berisi XSD untuk setiap aktivitas, menghilangkan kebutuhan untuk tabel ActivityField. SiteActivity akan berisi nilai kunci XML sehingga setiap aktivitas untuk situs sekarang akan berada dalam satu baris.

Suatu kegiatan akan terlihat seperti ini (tapi saya belum menyempurnakannya sepenuhnya):

<SomeActivityType>
  <SomeDateField type="StartDate">2000-01-01</SomeDateField>
  <AnotherDateField type="EndDate">2011-01-01</AnotherDateField>
  <EmployeeId type="ResponsiblePerson">1234</EmployeeId>
  <SomeTextField>blah blah</SomeTextField>
  ...

Keuntungan:

  • XSD akan memvalidasi XML, menangkap kesalahan seperti meletakkan string di bidang angka di tingkat database, sesuatu yang tidak mungkin dengan skema lama yang menyimpan segala sesuatu di varchar.
  • Recordset KVP yang digunakan untuk membangun formulir web dapat dengan mudah direproduksi menggunakan select ... from ActivityXML.nodes('/SomeActivityType/*') as T(r)
  • Subquery xpath dari XML dapat digunakan untuk menghasilkan set hasil yang memiliki kolom untuk tanggal mulai, tanggal akhir, dll tanpa menggunakan pivot, sesuatu seperti select ActivityXML.value('.[@type=StartDate]', 'datetime') as StartDate, ActivityXML.value('.[@type=EndDate]', 'datetime') as EndDate from SiteActivity where...

Apakah ini sepertinya ide yang bagus? Saya tidak bisa memikirkan cara lain untuk menyimpan sejumlah besar set properti yang berbeda. Pikiran lain yang saya miliki adalah menjaga skema yang ada dan menerjemahkannya menjadi sesuatu yang lebih mudah di-query di gudang data, tetapi saya belum pernah merancang skema bintang sebelumnya dan tidak tahu harus mulai dari mana.

Pertanyaan tambahan: Jika saya mendefinisikan tag sebagai memiliki tipe data tanggal dalam XSD menggunakan xs:date, apakah SQL Server akan mengindeksnya sebagai nilai tanggal? Saya khawatir jika saya kueri berdasarkan tanggal, maka string tanggal harus dilemparkan ke nilai tanggal dan menghancurkan peluang menggunakan indeks.

Paul Abbott
sumber
Seberapa up-to-date data untuk laporan perlu? Apakah laporan akan mengenai produksi?
James Anderson
Sebagian besar laporan mengenai gudang data sekarang (yang sebenarnya bukan DW, pada dasarnya merupakan salinan dari skema transaksional produksi dengan sejumlah tampilan dan tabel dari database lain yang ditambahkan). Memiliki laporan yang ketinggalan zaman dapat diterima, tetapi itu akan menjadi bonus jika dapat ditayangkan.
Paul Abbott
Berapa banyak tumpang tindih yang ada di ladang? Apakah sepuluh bidang mencakup semua 100 subtipe, atau ada ~ 500 bidang yang sepenuhnya berbeda?
Jon of All Trades
Ada 72 bidang dan 75 jenis aktivitas. 30 bidang hanya digunakan oleh satu aktivitas, dan sebagian besar sisanya digunakan oleh 5-10 aktivitas. Ada beberapa bidang yang digunakan oleh ~ 30 aktivitas berbeda. Sebagian besar, tidak ada banyak kesamaan di seluruh kegiatan.
Paul Abbott

Jawaban:

7

Jadi yang saya cari adalah cara untuk menyimpan sejumlah besar kegiatan yang hampir tidak memiliki bidang yang sama sehingga membuat pelaporan menjadi lebih mudah.

Tidak cukup perwakilan untuk berkomentar dulu, jadi kita mulai!

Jika tujuan utamanya adalah pelaporan dan Anda memiliki DW (bahkan jika itu bukan skema bintang) Saya akan merekomendasikan mencoba memasukkan ini ke skema bintang. Manfaatnya cepat, pertanyaan sederhana. Kelemahannya adalah ETL, tetapi Anda sudah mempertimbangkan untuk memindahkan data ke desain baru dan skema ETL ke bintang cenderung lebih mudah untuk dibangun dan dipelihara daripada solusi pembungkus XML (dan SSIS termasuk dalam lisensi SQL Server Anda). Plus itu memulai proses desain pelaporan / analitik yang diakui.

Jadi bagaimana melakukan itu ... Sepertinya Anda memiliki apa yang dikenal sebagai Fakta Tanpa Fakta . Ini adalah persimpangan atribut yang menentukan peristiwa tanpa ukuran yang terkait (seperti harga penjualan). Anda memiliki tanggal yang tersedia untuk sebagian atau semua kegiatan Anda? Kemungkinan Anda harus benar-benar memiliki persimpangan dari suatu Kegiatan, Situs, dan Tanggal.

DimActivity- Saya menduga ada pola, sesuatu yang dapat memungkinkan Anda untuk memecah ini menjadi setidaknya kolom yang relatif dibagikan. Jika demikian, Anda mungkin punya tiga? lima? dimensi untuk kelas kegiatan. Paling buruk Anda memiliki beberapa kolom yang konsisten, seperti nama aktivitas, Anda dapat memfilter, dan Anda meninggalkan judul umum seperti "Atribut1" dll. Untuk detail acak yang tersisa.

Anda tidak memerlukan semua yang ada di dimensi - ada (kemungkinan) tidak boleh ada tanggal dalam dimensi Aktivitas - mereka semua harus dalam kenyataan, seperti referensi Kunci pengganti ke dimensi Tanggal. Sebagai contoh, Tanggal yang akan tetap dalam dimensi seseorang akan menjadi tanggal lahir karena itu adalah atribut seseorang. Tanggal kunjungan rumah sakit akan berada dalam fakta, karena itu adalah titik waktu peristiwa yang terkait dengan seseorang, antara lain, tetapi itu bukan atribut dari orang yang mengunjungi rumah sakit. Lebih banyak diskusi tanggal sebenarnya.

DimSite- tampaknya lurus ke depan, jadi kami akan menjelaskan Kunci Pengganti di sini. Pada dasarnya ini hanya ID yang bertambah dan unik. Kolom Integer Identity adalah umum. Ini memungkinkan pemisahan DW dan sistem sumber dan memastikan penggabungan optimal dalam data warehouse. Kunci Alami atau Kunci Bisnis Anda biasanya disimpan, tetapi untuk pemeliharaan / desain bukan analisis dan bergabung. Contoh skema:

CREATE TABLE [DIM].[Site]
(
 SiteSK INT NOT NULL IDENTITY PRIMARY KEY
,SiteNK INT NOT NULL --source system key
,SiteName VARCHAR(500) NOT NULL
)

DimDate- atribut tanggal. Buat "kunci pintar" dan bukan Identitas. Ini berarti Anda dapat mengetik bilangan bulat bermakna yang berhubungan dengan tanggal untuk kueri seperti WHERE DateSK = 20150708. Ada banyak skrip gratis untuk memuat DimDate dan sebagian besar sudah menyertakan kunci pintar ini. ( satu opsi )

DimEmployee - XML ​​Anda termasuk ini, jika itu perubahan yang lebih umum ke DimPerson, dan isi dengan atribut orang yang relevan karena tersedia dan terkait dengan pelaporan.

Dan fakta Anda adalah:

FactActivitySite
DimSiteSK - FK to DimSite
DimActivitySK - FK to DimActivity
DimEmployee - FK to DimEmployee
DimDateSK - FK to DimDate

Anda bisa mengganti nama ini di Fakta, dan Anda bisa memiliki beberapa kunci tanggal per peristiwa. Fakta biasanya sangat besar sehingga menghindari pembaruan biasanya baik ... jika Anda memiliki beberapa pembaruan tanggal untuk satu peristiwa, Anda mungkin ingin mencoba desain Hapus / Sisipkan dengan menambahkan SK pada fakta yang memungkinkan pemilihan baris "perbarui" untuk dihapus lalu masukkan data terbaru.

Memperluas tanggal Fakta Anda untuk apa pun yang Anda butuhkan: StartDateSK, EndDateSK, ScheduledStartDateSK.

Semua dimensi harus memiliki baris Tidak Dikenal biasanya dengan hardcod -1 SK. Ketika Anda memuat fakta, dan suatu aktivitas tidak memiliki Tanggal yang dimasukkan, itu hanya memuat -1.

Faktanya adalah kumpulan referensi bilangan bulat untuk atribut Anda yang disimpan dalam dimensi, bergabung bersama-sama dan Anda mendapatkan semua detail Anda, dalam pola gabungan yang sangat bersih, dan faktanya, karena tipe datanya, sangat kecil dan cepat. Karena Anda berada di SQL Server, tambahkan indeks kolom toko untuk meningkatkan kinerja lebih lanjut. Anda bisa menjatuhkannya dan membangun kembali selama ETL. Setelah Anda masuk ke SQL 2014+ Anda dapat menulis ke indeks kolomstore.

masukkan deskripsi gambar di sini

Jika Anda mengikuti penelitian rute ini, Dimensional Modeling. Saya akan merekomendasikan metodologi Kimball . Ada banyak panduan gratis di luar sana juga, tetapi jika ini akan menjadi apa pun selain solusi satu kali, investasi kemungkinan akan sepadan.

Dave
sumber
(pertanyaan dari wesdev): @Dave, alat ERD apa yang Anda gunakan?
ypercubeᵀᴹ
Ini dilakukan di Microsoft Visio 2013
Dave