Saya sedang mengembangkan database SQL Server 2012 dan saya ragu tentang kolom nvarchar sebagai kunci utama.
Saya punya tabel ini:
CREATE TABLE [dbo].[CODES]
(
[ID_CODE] [bigint] IDENTITY(1,1) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
[CODE] [nvarchar](20) NOT NULL,
[FLAG] [tinyint] NOT NULL,
[IS_TRANSMITTED] [bit] NOT NULL DEFAULT 0,
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE_LEVEL] ASC,
[CODE] ASC
)
)
Tapi sekarang saya ingin menggunakan [CODE]
kolom sebagai kunci utama dan menghapus [ID_CODE]
kolom.
Apakah ada masalah atau hukuman jika saya memiliki NVARCHAR
kolom PRIMARY KEY
?
[CODE]
nilai kolom harus unik, jadi saya pikir saya bisa menetapkan UNIQUE
batasan untuk kolom itu.
Apakah saya harus menggunakan [CODE]
sebagai kunci utama atau lebih baik jika saya menetapkan UNIQUE
batasan pada [CODE]
kolom?
sql-server
primary-key
unique-constraint
VansFannel
sumber
sumber
CODE
kolom Anda harus unik, tetapi bukan Kunci Utama. Saya menduga itu membawa informasi. Jika informasi itu dapat diubah, maka AndaCODE
harus berubah atau ketinggalan zaman. Itu akan membuat Kunci Utama Anda mudah menguap, dan saya tidak bisa melihat itu berakhir dengan baik. Yang terbaik adalah membiarkan PK Anda hanya menjadi kunci, dan KODE Anda dapat melakukan apa yang disukainya. Hanya sebuah opini.Jawaban:
Ya, benar-benar ada konsekuensi negatif untuk menggunakan string, bukan tipe numerik untuk Kunci Utama, dan terlebih lagi jika PK itu Clustered (yang memang dalam kasus Anda). Namun, sejauh mana Anda melihat efek (s) menggunakan bidang string adalah fungsi dari a) berapa banyak baris dalam tabel ini, dan b) berapa banyak baris dalam tabel lain yang Asing Kunci untuk PK ini. Jika Anda hanya memiliki 10k baris di tabel ini dan 100k baris di beberapa tabel lain yang FK ke tabel ini melalui bidang itu, maka mungkin itu tidak akan begitu terlihat. Tetapi efek-efek itu tentu saja menjadi lebih nyata ketika jumlah baris meningkat.
Anda perlu mempertimbangkan bahwa bidang dalam Indeks Clustered dibawa ke Indeks Non-Clustered. Jadi Anda tidak hanya melihat hingga 40 byte per baris, tetapi (40 * some_number) byte. Dan di setiap tabel FK Anda memiliki 40 byte yang sama di baris plus lebih sering daripada tidak akan ada indeks Non-Clustered pada bidang itu seperti yang digunakan dalam GABUNGAN, jadi sekarang benar-benar dua kali lipat dalam setiap tabel yang FK untuk yang ini. Jika seseorang cenderung berpikir bahwa 40 byte * 1 juta baris * 10 salinannya tidak perlu dikhawatirkan, silakan lihat artikel saya Disk Is Cheap! ORLY? yang merinci semua (atau paling tidak sebagian besar) area yang terkena dampak keputusan ini.
Hal lain yang perlu dipertimbangkan adalah bahwa pemfilteran dan pengurutan pada string, terutama ketika tidak menggunakan Kolasi biner (saya berasumsi Anda menggunakan default database yang biasanya case-insensitive) jauh lebih efisien (yaitu membutuhkan waktu lebih lama) daripada ketika menggunakan
INT
/BIGINT
. Ini memengaruhi semua kueri yang memfilter / bergabung / mengurutkan di bidang ini.Oleh karena itu, menggunakan sesuatu seperti
CHAR(5)
mungkin akan baik-baik saja untuk PK Clustered, tetapi kebanyakan jika itu juga didefinisikan denganCOLLATE Latin1_General_100_BIN2
(atau sesuatu seperti itu).Dan dapatkah nilai
[CODE]
berubah? Jika ya maka itu adalah alasan yang lebih besar untuk tidak menggunakannya sebagai PK (bahkan jika Anda mengatur agar FKON UPDATE CASCADE
). Jika tidak bisa atau tidak akan pernah berubah itu baik-baik saja, tetapi masih ada lebih dari cukup alasan untuk tidak menggunakannya sebagai PK Clustered.Tentu saja, pertanyaannya mungkin tidak tepat diungkapkan karena tampaknya Anda sudah memiliki bidang ini di PK Anda.
Apapun, pilihan terbaik Anda, sejauh ini, adalah menggunakan
[ID_CODE]
sebagai PK Clustered, gunakan bidang itu dalam tabel terkait sebagai FK, dan simpan[CODE]
sebagaiUNIQUE INDEX
(yang berarti itu adalah "kunci alternatif").Perbarui
sedikit lebih banyak info berdasarkan pertanyaan ini di komentar pada jawaban ini:
Ini semua tergantung pada banyak faktor, beberapa di antaranya telah saya sebutkan tetapi akan menyatakan kembali:
Kunci Utama adalah bagaimana setiap baris diidentifikasi, terlepas apakah itu dirujuk oleh Kunci Asing atau tidak. Bagaimana sistem Anda mengidentifikasi baris secara internal terkait dengan, tetapi tidak harus sama dengan, bagaimana pengguna Anda mengidentifikasi diri / baris itu. Setiap kolom TIDAK NULL dengan data unik dapat berfungsi, tetapi ada masalah kepraktisan yang perlu dipertimbangkan, terutama jika PK, pada kenyataannya, dirujuk oleh setiap FK. Misalnya GUID unik dan beberapa orang sangat suka menggunakannya karena berbagai alasan, tetapi mereka cukup buruk untuk Indeks Clustered (
NEWSEQUENTIALID
lebih baik, tetapi tidak sempurna). Di sisi lain, GUID baik-baik saja sebagai kunci alternatif dan digunakan oleh aplikasi untuk mencari baris, tetapi GABUNGAN masih dilakukan dengan menggunakan INT (atau yang serupa) PK.Sejauh ini Anda belum memberi tahu kami bagaimana
[CODE]
bidang cocok ke sistem dari semua sudut, di luar sekarang menyebutkan bahwa ini adalah bagaimana Anda mencari baris, tetapi apakah itu untuk semua pertanyaan atau hanya beberapa? Karenanya:Mengenai
[CODE]
nilai:Mengenai tabel ini:
[CODE]
atau[ID_CODE]
) digunakan dalam tabel lain, meskipun tidak secara eksplisit Asing Kunci?[CODE]
satu-satunya bidang yang digunakan untuk mendapatkan baris individual, lalu tujuan apa yang[ID_CODE]
dilayani bidang tersebut? Jika tidak digunakan, mengapa harus di tempat pertama (yang mungkin tergantung pada jawaban untuk "Bisakah[CODE]
bidang berubah?")?Keputusan ini tidak dapat dibuat murni berdasarkan pertanyaan "NVARCHAR ya atau tidak?". Saya lagi akan mengatakan bahwa secara umum saya tidak menganggapnya sebagai ide yang baik, tetapi ada kalanya tidak masalah. Mengingat begitu sedikit bidang dalam tabel ini, tidak mungkin ada lebih banyak, atau setidaknya tidak banyak, indeks. Jadi Anda mungkin baik-baik saja untuk memiliki
[CODE]
Indeks Clustered. Dan jika tidak ada tabel lain referensi tabel ini maka Anda mungkin juga baik-baik saja menjadikannya PK. Tapi, jika tabel lain merujuk tabel ini maka saya akan memilih[ID_CODE]
bidang sebagai PK, bahkan jika Non-Clustered.sumber
[ID_CODE]
, sebagaiPRIMARY KEY
, opsi terbaik jika saya menggunakan[CODE]
kolom untuk mencari tabel?Anda harus memisahkan konsep:
kunci utama adalah konsep desain , properti logis dari entri dalam tabel. Itu harus tetap selama masa entri tabel, dan harus menjadi kunci yang digunakan dalam aplikasi untuk referensi entri.
indeks berkerumun adalah konsep penyimpanan , properti fisik. Itu harus menjadi jalur akses paling umum untuk kueri, itu harus berfungsi untuk memenuhi sebagai meliputi indeks untuk sebagian besar kasus, dan memenuhi sebanyak mungkin berbagai kueri.
Tidak diperlukan kunci primer untuk menjadi indeks berkerumun. Anda dapat memiliki
ID_CODE
sebagai PK dan(CODE_LEVEL, CODE)
sebagai kunci berkerumun. Atau sebaliknya.Kunci cluster yang lebih besar memiliki beberapa dampak negatif, karena kunci yang lebih luas berarti kepadatan yang lebih rendah pada halaman indeks dan ukuran yang lebih besar dikonsumsi pada semua indeks non-cluster. sudah ada banyak tinta yang tumpah pada topik ini, misalnya. mulai dari Lebih banyak pertimbangan untuk kunci pengelompokan - perdebatan indeks berkerumun berlanjut! .
Tetapi intinya adalah bahwa pilihan kunci indeks berkerumun adalah trade-off. Di satu sisi Anda memiliki persyaratan ukuran penyimpanan, dengan dampak umum kinerja (key yang lebih besar -> ukuran yang lebih besar -> lebih IO, dan IO bandwidth mungkin yang sumber daya yang paling langka Anda memiliki). Di sisi lain memilih kunci berkerumun yang salah atas nama penghematan ruang dapat memiliki konsekuensi kinerja kueri, seringkali lebih buruk daripada masalah yang dihasilkan dari kunci lebar.
Adapun pilihan kunci utama, seharusnya tidak menjadi masalah: model data Anda, logika aplikasi Anda, harus menentukan apa kunci utama itu.
Yang sedang berkata, 2c saya:
NVARCHAR(20)
ini tidak lebar. Merupakan ukuran kunci cluster yang dapat diterima, bahkan untuk meja besar.sumber
[ID_CODE]
, sebagaiPRIMARY KEY
, opsi terbaik jika saya menggunakan[CODE]
kolom (dan mungkin[CODE_LEVEL]
) untuk melihat tabel?[CODE]
kolom sebagai KUNCI UTAMA.Saya tidak akan pernah mengizinkan siapa pun
nvarchar(20)
untuk menjadi seorang PK di database saya. Anda membuang ruang disk dan memori cache. Setiap indeks pada tabel ini dan semua FK untuknya mereplikasi nilai luas ini. Mungkin char (20) jika mereka bisa membenarkannya. Data apa yang Anda coba simpanCODE
? Apakah Anda benar-benar perlu menyimpan karakter nvarchar? Saya cenderung membuat nilai PK "internal" tidak terlihat oleh pengguna, dan saya mencoba untuk menjaga nilai yang ditampilkan terpisah. Nilai yang ditampilkan terkadang perlu diubah, yang menjadi sangat bermasalah dengan PK + FK.Juga, apakah Anda menyadari bahwa 'identitas bigint (1,1)' dapat meningkat hingga 9.223.372.036.854.775.807?
Kecuali jika Anda membangun basis data ini untuk Google, bukankah normal
int identity (1,1)
dengan batas lebih dari 2 Milyarnya sudah cukup?sumber
[ID_CODE]
, sebagaiPRIMARY KEY
, opsi terbaik jika saya menggunakan[CODE]
kolom untuk mencari tabel? Terima kasih.Seharusnya tidak ada hukuman inheren / nyata selain Anda berisiko menggunakan kunci lebar saat menggunakan nvarchar / varchar jika tidak sadar. Terutama jika Anda mulai menggabungkannya dengan kunci komposit.
Tetapi dalam contoh Anda (20) panjang Anda harus baik-baik saja dan saya tidak akan terlalu khawatir tentang hal itu. Karena jika CODE adalah bagaimana Anda terutama meminta data Anda - indeks berkerumun pada itu terdengar sangat masuk akal.
Namun, Anda harus mempertimbangkan apakah Anda benar-benar menginginkannya sebagai kunci utama atau hanya indeks unik (berkerumun). Ada perbedaan (kecil) antara indeks berkerumun dan kunci utama (pada dasarnya - kunci utama mengidentifikasi data Anda, tetapi indeks adalah cara Anda melakukan kueri data), jadi jika Anda mau, Anda bisa dengan mudah menjadikan ID_Code Anda sebagai kunci utama dan buat indeks berkerumun unik di atas KODE. (perhatikan: SQL Server akan secara otomatis membuat Kunci Utama Anda menjadi indeks berkerumun, kecuali Anda telah membuat sendiri indeks berkerumun secara manual)
Juga pertimbangkan apakah Anda benar-benar membutuhkan ID_Code sekarang Anda memiliki KODE yang unik.
sumber
NVARCHAR(20)
adalah 40 byte dalam ukuran (maks), dan karena itu kolom panjang variabel , itu bukan pilihan terbaik untuk indeks berkerumun.ID_CODE
menjadiBIGINT IDENTITY
akan menjadi pilihan yang jauh lebih baik di sini!