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)
Jawaban:
Selain ruang disk tambahan (dan pada gilirannya penggunaan memori dan I / O), tidak ada salahnya menambahkan kolom IDENTITY bahkan ke tabel yang tidak membutuhkannya (contoh tabel yang tidak memerlukan kolom IDENTITY adalah tabel persimpangan sederhana, seperti memetakan pengguna ke izinnya).
Saya menolak menambahkan secara membabi buta ke setiap tabel dalam posting blog dari 2010:
Tetapi kunci pengganti memang memiliki kasus penggunaan yang valid - hanya berhati-hati untuk tidak menganggap bahwa mereka menjamin keunikan (yang kadang-kadang mengapa mereka ditambahkan - mereka seharusnya bukan satu - satunya cara untuk secara unik mengidentifikasi baris). Jika Anda perlu menggunakan kerangka kerja ORM, dan kerangka kerja ORM Anda memerlukan kunci integer satu kolom bahkan dalam kasus ketika kunci asli Anda bukan bilangan bulat, atau tidak satu kolom, atau tidak, pastikan Anda mendefinisikan batasan / indeks unik untuk kunci Anda yang sebenarnya juga.
sumber
Dari pengalaman saya, alasan utama dan luar biasa untuk menggunakan ID terpisah untuk setiap tabel adalah sebagai berikut:
Dalam hampir setiap kasus pelanggan saya bersumpah darah dalam fase konsepsi bahwa beberapa bidang "alami" eksternal
XYZBLARGH_ID
akan tetap unik selamanya, dan tidak akan pernah berubah untuk entitas tertentu, dan tidak akan pernah digunakan kembali, akhirnya muncul kasus di mana Properti Primary Key rusak. Itu tidak berhasil seperti itu.Kemudian, dari sudut pandang DBA, hal-hal yang membuat DB lambat atau kembung tentu bukan 4 byte (atau apa pun) per baris, tetapi hal-hal seperti indeks yang salah atau hilang, reorganisasi tabel / indeks yang dilupakan, RAM yang salah / parameter pengaturan ruang tablespace , lalai untuk menggunakan variabel bind dan sebagainya. Itu bisa memperlambat DB dengan faktor 10, 100, 10000 ... bukan kolom ID tambahan.
Jadi, bahkan jika ada kelemahan teknis dan terukur dari memiliki tambahan 32 bit per baris, itu bukan pertanyaan apakah Anda dapat mengoptimalkan ID pergi, tetapi apakah ID akan sangat penting di beberapa titik, yang akan lebih mungkin daripada tidak. Dan saya tidak akan menghitung semua manfaat "lunak" dari pendirian pengembangan perangkat lunak (seperti contoh ORM Anda, atau fakta bahwa hal itu membuatnya lebih mudah bagi pengembang perangkat lunak ketika semua ID dengan desain memiliki tipe data yang sama dan seterusnya) .
NB: perhatikan bahwa Anda tidak memerlukan ID terpisah untuk
n:m
tabel asosiasi karena untuk tabel seperti itu ID entitas terkait harus membentuk kunci utama. Contoh tandingan akan menjadin:m
asosiasi aneh yang memungkinkan banyak asosiasi antara dua entitas yang sama untuk alasan aneh apa pun - mereka akan memerlukan kolom ID mereka sendiri kemudian, untuk membuat PK. Ada yang ORM perpustakaan yang tidak dapat menangani PKS multi-kolom, jadi itu akan menjadi alasan untuk bersikap lunak dengan pengembang, jika mereka harus bekerja dengan perpustakaan tersebut.sumber
Jika Anda selalu menambahkan kolom tambahan yang tidak berarti ke setiap tabel dan hanya merujuk kolom-kolom itu sebagai kunci asing maka Anda hampir pasti akan membuat basis data lebih kompleks dan sulit digunakan. Secara efektif Anda akan menghapus data yang menarik bagi pengguna dari atribut kunci asing dan memaksa pengguna / aplikasi untuk melakukan join tambahan untuk mengambil informasi yang sama. Pertanyaan menjadi lebih kompleks, pekerjaan pengoptimal menjadi lebih sulit dan kinerja dapat menurun.
Tabel Anda akan lebih jarang diisi dengan data "nyata" daripada sebelumnya. Oleh karena itu, basis data akan lebih sulit untuk dipahami dan diverifikasi. Anda juga mungkin merasa sulit atau tidak mungkin untuk menegakkan batasan berguna tertentu (di mana kendala akan melibatkan banyak atribut yang tidak lagi ada dalam tabel yang sama).
Saya sarankan Anda memilih kunci Anda lebih hati-hati dan membuatnya bilangan bulat hanya jika / ketika Anda punya alasan bagus untuk itu. Basis desain database Anda pada analisis yang baik, integritas data, kepraktisan, dan hasil yang dapat diverifikasi daripada mengandalkan aturan dogmatis.
sumber
Dalam pengalaman saya dengan berbagai database, kunci primer Integer selalu lebih baik daripada aplikasi yang tidak memiliki kunci yang ditentukan sama sekali. Atau yang memiliki kunci yang bergabung dengan setengah lusin kolom varchar dengan cara canggung yang tidak logis ... (huh)
Saya telah melihat aplikasi yang beralih dari PK integer ke GUID. Alasan mereka melakukan itu adalah karena ada kebutuhan untuk menggabungkan data dari beberapa sumber database dalam kasus-kasus tertentu. Pengembang mengalihkan semua kunci ke GUID sehingga penggabungan dapat terjadi tanpa takut akan tabrakan data, bahkan pada tabel yang bukan bagian dari penggabungan (kalau-kalau tabel tersebut pernah menjadi bagian dari penggabungan di masa mendatang).
Saya akan mengatakan integer PK tidak akan menggigit Anda kecuali jika Anda berencana untuk menggabungkan data dari sumber yang berbeda atau Anda mungkin memiliki data yang melampaui batas ukuran integer Anda - semuanya menyenangkan dan permainan sampai Anda kehabisan ruang untuk memasukkan .
Saya akan mengatakan, meskipun, bahwa itu bisa masuk akal untuk mengatur indeks berkerumun Anda pada kolom selain PK Anda, jika tabel akan bertanya lebih sering seperti itu. Tapi itu kasus outliar, terutama jika sebagian besar pembaruan dan pemilihan didasarkan pada nilai-nilai PK.
sumber
Kesampingkan:
Asalkan Anda menggunakan penghapusan massal / pembaruan di mana sesuai, dan memiliki indeks untuk mendukung operasi tersebut, saya tidak berpikir Anda akan mengalami masalah karena standar PK yang Anda gunakan.
Mungkin saja jika nanti Anda memiliki EF menghasilkan kueri dengan bergabung dll, bahwa mereka tidak akan seefisien mereka dengan repositori berbasis kunci alam, tapi saya tidak cukup tahu tentang area itu untuk mengatakan dengan pasti.
sumber
Anda memiliki beberapa faktor untuk membantu membimbing Anda,
Definisi dan spesifikasi.
Jika sesuatu didefinisikan unik oleh tugas atau hukum fisika, Anda membuang-buang waktu dengan kunci pengganti.
Keunikan.
Untuk kewarasan pribadi, bergabung, dan fungsionalitas basis data tingkat tinggi, Anda akan memerlukan, (a) kolom unik, (b) serangkaian kolom unik
Semua skema normalisasi cukup (1NF) menyediakan salah satu dari berikut ini. Jika tidak, Anda harus selalu membuatnya. Jika Anda memiliki daftar orang yang akan menjadi sukarelawan pada hari Minggu, dan itu termasuk nama belakang dan nama depan, Anda akan ingin tahu kapan Anda memiliki dua Joe Bobs.
Implementasi dan optimalisasi.
Int cenderung menjadi bentuk data kecil yang cepat untuk perbandingan, dan kesetaraan. Bandingkan dengan string Unicode yang collation-nya dapat bergantung pada lokal (lokasi dan bahasa). Menyimpan 4242 dalam string ASCII / UTF8 adalah 4 byte. Menyimpannya sebagai integer cocok dalam 2 byte.
Jadi ketika datang ke kerugian Anda punya beberapa faktor.
Kebingungan dan ambiguitas.
Ruang.
Integer masih menambah ruang pada baris. Dan, jika Anda tidak menggunakannya tidak ada tujuan.
Clustering
Anda hanya dapat memesan data satu arah. Jika Anda memaksakan kunci pengganti yang tidak diperlukan, apakah Anda mengelompok seperti itu atau cara kunci alami?
sumber