Dalam satu aplikasi Web yang saya kerjakan, semua operasi basis data diabstraksi menggunakan beberapa repositori generik yang didefinisikan melalui Entity Framework ORM.
Namun, untuk memiliki desain sederhana untuk repositori generik, semua tabel yang terlibat harus mendefinisikan integer unik ( Int32
dalam C #, int
dalam SQL). Sampai sekarang, ini selalu menjadi PK tabel dan juga IDENTITY
.
Kunci asing banyak digunakan dan mereferensikan kolom integer ini. Mereka diperlukan untuk konsistensi dan untuk menghasilkan properti navigasi oleh ORM.
Lapisan aplikasi biasanya melakukan operasi berikut:
- pemuatan data awal dari tabel (*) -
SELECT * FROM table
- Perbarui -
UPDATE table SET Col1 = Val1 WHERE Id = IdVal
- Hapus -
DELETE FROM table WHERE Id = IdVal
- Sisipkan -
INSERT INTO table (cols) VALUES (...)
Operasi yang lebih jarang:
- Sisipan massal -
BULK INSERT ... into table
diikuti (*) oleh semua data yang dimuat (untuk mengambil pengidentifikasi yang dihasilkan) - Hapus massal - ini adalah operasi penghapusan normal, tetapi "besar" dari perspektif ORM:
DELETE FROM table where OtherThanIdCol = SomeValue
- Pembaruan massal - ini adalah operasi pembaruan normal, tetapi "besar" dari perspektif ORM:
UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue
* semua tabel kecil di-cache di level aplikasi dan hampir semua SELECTs
tidak akan mencapai basis data. Pola tipikal adalah beban awal dan banyak INSERT
s, UPDATE
s dan DELETE
s.
Berdasarkan penggunaan aplikasi saat ini, ada kemungkinan sangat kecil untuk mencapai 100 juta catatan di salah satu tabel.
Pertanyaan: Dari sudut pandang DBA, apakah ada masalah signifikan yang dapat saya hadapi dengan memiliki batasan desain tabel ini?
[EDIT]
Setelah membaca jawabannya (terima kasih atas umpan baliknya yang luar biasa) dan artikel yang direferensikan, saya merasa harus menambahkan rincian lebih lanjut:
Khusus aplikasi saat ini - Saya tidak menyebutkan tentang aplikasi web saat ini, karena saya ingin memahami apakah model tersebut dapat digunakan kembali untuk aplikasi lain juga. Namun, kasus khusus saya adalah aplikasi yang mengekstrak banyak metadata dari DWH. Sumber data sangat berantakan (didenormalkan dengan cara yang aneh, memiliki beberapa inkonsistensi, tidak ada pengidentifikasi alami dalam banyak kasus, dll.) Dan aplikasi saya menghasilkan entitas yang jelas terpisah. Juga, banyak pengidentifikasi yang dihasilkan (
IDENTITY
) ditampilkan, sehingga pengguna dapat menggunakannya sebagai kunci bisnis. Ini, selain refactoring kode besar-besaran, tidak termasuk penggunaan GUID ."mereka seharusnya tidak menjadi satu-satunya cara untuk mengidentifikasi secara unik satu baris" (Aaron Bertrand ♦) - itu adalah saran yang sangat bagus. Semua tabel saya juga mendefinisikan KONSTRA UNIK untuk memastikan bahwa duplikat bisnis tidak diperbolehkan.
Desain berbasis aplikasi front-end vs. desain berbasis database - pilihan desain disebabkan oleh faktor-faktor ini
Batasan Entity Framework - beberapa kolom PK diizinkan, tetapi nilainya tidak dapat diperbarui
Batasan khusus - memiliki kunci integer tunggal sangat menyederhanakan struktur data dan kode non-SQL. Misalnya: semua daftar nilai memiliki kunci integer dan nilai yang ditampilkan. Lebih penting, itu menjamin bahwa setiap tabel yang ditandai untuk caching akan dapat dimasukkan ke dalam
Unique int key -> value
peta.
Kueri pemilihan kompleks - ini hampir tidak akan pernah terjadi karena semua data tabel kecil (<20-30K catatan) di-cache di tingkat aplikasi. Ini membuat hidup sedikit lebih sulit ketika menulis kode aplikasi (lebih sulit untuk menulis LINQ), tetapi basis datanya lebih baik:
Tampilan daftar - tidak akan menghasilkan
SELECT
kueri saat dimuat (semuanya di-cache) atau kueri yang terlihat seperti ini:SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)
Semua nilai lain yang diperlukan diambil melalui pencarian cache (O (1)), sehingga tidak ada permintaan kompleks yang akan dihasilkan.
Edit tampilan - akan menghasilkan
SELECT
pernyataan seperti ini:SELECT allcolumns FROM BigTable WHERE PKId = value1
(semua filter dan nilai adalah int
s)