Manakah dari desain tabel ini yang lebih baik untuk kinerja?


16

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 monthadalah 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


Jadi dapatkan disk lain. Disk murah. Anda dapat meminta 2TB untuk biaya rapat untuk berdebat tentang hal ini.

Jawaban:


9

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


3
@ Rachel Saya pasti akan merekomendasikan menerapkan skema partisi dengan set data yang besar ini. Jika mereka fokus pada bulan ke bulan bekerja dan melaporkan maka yang terbaik adalah memilih kunci partisi yang dapat bertepatan dengan pola pikir itu. Selain itu, jika Anda mengkonfigurasi partisi dengan benar, Anda dapat dengan mudah memindahkan data masuk dan keluar dari tabel ke tabel pementasan yang membuat banyak data dan penghapusan untuk menggulirkan data membuat snap yang membutuhkan detik, bukan jam.
David

6

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.


4

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).


SPARSE - Ini adalah poin yang sangat bagus yang membuat semua perbedaan. Jika jarang, Anda menghemat ruang dengan normalisasi. Kalau tidak, tidak. Tetapi ruang disk murah, jadi saya pribadi memilih untuk fleksibilitas maksimum (dinormalisasi).

3

Terlepas dari manfaat kinerja, saya pasti akan mendukung opsi 1. Opsi 2 akan merampok Peter untuk membayar Paul, menurut pendapat saya.


2

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).


0

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:

AccountDate
-----------
AccountId  
Date  
AcDtID (surrogate key)

Costs
-------
AcDtID
CostTypeId  
Amount  

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.


Saya ada TotalCostdi sana karena mayoritas pelaporan dirangkum, dan saya pikir akan lebih cepat untuk meminta nilai tunggal daripada menambahkan 13 nilai yang berbeda.

Mungkin, tetapi kemudian Anda benar-benar memperkenalkan ketergantungan transitif. Apakah catatan-catatan itu akan diperbarui? atau hanya ditulis dan kemudian hanya dibaca?

Catatan akan diperbarui setiap kali biaya baru diterapkan pada rentang tanggal tersebut. Setelah sekitar satu bulan tidak mungkin bahwa total biaya akan diperbarui, tetapi masih mungkin karena hal-hal seperti biaya dukungan tahunan.

Maka setiap pembaruan akan membutuhkan 2 pembaruan, dan bidang TotalCost menambah risiko ketidakkonsistenan.

Ketergantungan transitif, tetapi tidak selalu merupakan risiko ketidakkonsistenan - batasan CHECK () dapat menjamin bahwa TotalCost selalu merupakan jumlah biaya.
Mike Sherrill 'Cat Recall'

0

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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.