Saya telah diminta untuk membuat sesuatu yang melacak biaya harian untuk dikumpulkan di akun, dan saya mencoba mencari skema tabel database yang akan mendukung ini.
Inilah yang saya tahu
- Perusahaan memiliki lebih dari 2,5 juta akun
- Dari jumlah tersebut, mereka saat ini bekerja rata-rata 200.000 per bulan (yang berubah dengan tingkat kepegawaian, yang saat ini rendah)
- Mereka memiliki 13 jenis biaya berbeda yang ingin mereka lacak, dan mereka telah memperingatkan bahwa mereka mungkin menambahkan lebih banyak di masa depan
- Mereka ingin biaya dilacak setiap hari
- Biaya tidak dibagi di seluruh inventaris. Entah itu dibagi berdasarkan # akun yang dikerjakan per bulan (200.000), atau pengguna dapat memasukkan pengenal akun untuk menerapkan biaya pada sekelompok akun, atau mereka dapat dengan mudah menentukan akun mana yang akan dikenakan biaya.
Pikiran pertama saya adalah database yang dinormalisasi:
ID Akun Tanggal CostTypeId Jumlah
Masalah saya dengan ini adalah, lakukan matematika. Tabel ini akan menjadi besar dengan cepat. Dengan asumsi semua 13 jenis biaya dapat diterapkan ke semua akun yang bekerja untuk bulan berjalan, itu 200k * 13 * N days in month
adalah sekitar 75-80 juta catatan per bulan, atau hampir satu miliar catatan per tahun.
Pikiran kedua saya adalah sedikit mendenormalisasi itu
ID Akun Tanggal Total biaya Jenis Biaya1 Jenis Biaya2 Jenis Biaya3 Jenis Biaya4 Jenis Biaya5 Jenis Biaya6 Jenis Biaya7 Jenis Biaya8 Jenis Biaya9 Jenis Biaya10 Jenis Biaya11 Jenis Biaya12 Jenis Biaya13
Metode ini lebih didenormalisasi dan dapat membuat hingga 6 juta catatan per bulan ( 200k * N days in month
), atau sekitar 72 juta per tahun. Ini jauh lebih sedikit daripada metode pertama, tetapi jika perusahaan memutuskan Jenis Biaya baru di masa depan, kolom database lain perlu ditambahkan.
Dari dua metode, mana yang Anda sukai? Mengapa? Apakah ada alternatif lain yang dapat Anda pikirkan yang akan menangani ini dengan lebih baik?
Saya paling tertarik untuk melaporkan kinerja, baik laporan musim panas dan detail. Pekerjaan yang akan menyebarkan biaya keluar dari akun akan dijalankan setiap malam ketika tidak ada orang di sekitar. Masalah kedua adalah ukuran basis data. Basis data yang ada sudah hampir 300GB, dan saya percaya ruang pada disk sekitar 500GB.
Basis datanya adalah SQL Server 2005
Jawaban:
Satu miliar catatan setahun tidak banyak.
Dengan mempartisi (mungkin menurut jenis biaya) dan pengarsipan dapat dikelola.
Jumlah item data yang akan disimpan masih 200k * 13 * N. Sebagai kolom, Anda akan mendapatkan lebih sedikit baris per halaman dan itu akan memakan lebih banyak ruang daripada sebagai baris. Anda bisa mendapatkan jika "CostType1" bukan tipe data panjang tetap, tetapi marginal.
"KISS" seperti kata mereka
sumber
Meskipun desain Anda pasti dapat membuat perbedaan malam atau siang, dalam hal ini saya akan lebih fokus pada indeks, termasuk mencakup indeks yang diperlukan. Saya juga akan melihat beberapa alat yang SQL Server memberi Anda untuk menangani tabel yang sangat besar, seperti tabel-partisi.
Pikirkan seperti ini, meskipun ada 80 miliar catatan di tabel, dengan pengindeksan yang tepat, yang Anda benar-benar tertarik pada suatu titik tertentu akan dikelompokkan bersama secara fisik pada disk. Karena cara data disusun dalam SQL server, data yang dipecah berdasarkan batas indeks mungkin juga berada di tabel lain karena tidak harus membaca seluruh tabel untuk mendapatkan apa yang dibutuhkan.
Jika Anda juga memilih untuk mempartisi tabel, Anda dapat meningkatkan waktu akses dan memasukkan waktu.
sumber
Saya akan menormalkan. Kami menghitung biaya untuk profitabilitas akun pelanggan di bank dan kami menghasilkan lebih dari 250 juta baris biaya individual menggunakan ratusan driver yang dialokasikan oleh pusat biaya atau oleh buku besar atau dengan berbagai teknik lain pada jutaan akun setiap bulan.
Misalnya, total biaya layanan ATM dibagi antara beberapa rekening yang telah menggunakan ATM berdasarkan jumlah penggunaan relatif. Jadi, jika $ 1 juta dihabiskan untuk melayani ATM dan hanya 5 pelanggan yang menggunakannya sekali masing-masing dan satu pelanggan menggunakannya 5 kali, maka satu pelanggan biaya bank $ 0,5 juta dan pelanggan lain biaya bank $, 1 juta masing-masing. Pengemudi lain mungkin jauh lebih kompleks.
Pada akhirnya, Anda mungkin akan menemukan itu jarang - akun tertentu tidak mendapatkan biaya dari sumber / driver tertentu - dan beberapa akun tidak mendapatkan apa-apa. Dalam model yang dinormalisasi, baris-baris itu tidak ada. Dalam model denormalized, baris ada, dengan beberapa kolom kosong. Juga, dalam model normal yang jarang, Anda akan melihat kinerja meningkat, karena keberadaan baris biasanya lebih cepat untuk diperiksa (dengan mencakup indeks pada CostType) daripada memeriksa semua baris dengan non-NULL dalam "ember" tertentu (bahkan dengan indeks pada setiap kolom jumlah - yang dapat Anda lihat mulai menjadi sangat boros).
sumber
Terlepas dari manfaat kinerja, saya pasti akan mendukung opsi 1. Opsi 2 akan merampok Peter untuk membayar Paul, menurut pendapat saya.
sumber
Saya akan menggunakan opsi 1, dan kemudian jika kecepatan pelaporan menjadi masalah di jalan saya juga akan menambahkan tabel 2, dan mengisi ke dalam database pelaporan dalam semacam proses semalam / offpeak otomatis.
Anda juga dapat mempertimbangkan menggulung struktur tabel-2 harian ke dalam rollup mingguan, bulanan, triwulanan, tahunan jika diperlukan.
Tetapi, seperti yang saya katakan, saya juga akan memilih untuk menyimpan data 'mentah' dalam bentuk yang tepat (dinormalisasi).
sumber
Mempertimbangkan volume yang Anda sebutkan, saya akan memilih opsi kedua, tetapi tanpa TotalCost. Bisa dibilang masih normal.
Edit: sebagai alternatif, dan tergantung pada kebutuhan Anda, dan ukuran dari AccountId, Anda juga dapat mempertimbangkan yang berikut:
Dengan desain itu, Anda masih bisa menambahkan TotalCost yang didenormalkan ke tabel pertama, dan membuatnya dihitung ulang setiap malam, memungkinkan untuk menjalankan beberapa laporan di tabel pertama saja.
sumber
TotalCost
di sana karena mayoritas pelaporan dirangkum, dan saya pikir akan lebih cepat untuk meminta nilai tunggal daripada menambahkan 13 nilai yang berbeda.Anda harus membagi tabel firs menjadi dua tabel sehingga Anda bisa menggunakan subquery dan memilih baris kedua sebagai kolom, atau banyak kolom. lebih fleksibel dengan cara itu dan dengan itu, Anda bisa mendapatkan hasil seperti yang kedua dengan lebih mudah.
sumber