Mengapa nilai kunci utama akan berubah?

18

Saya telah meneliti konsep ROWGUID baru-baru ini dan menemukan pertanyaan ini . Jawaban ini memberi wawasan, tetapi telah membawa saya ke lubang kelinci yang berbeda dengan menyebutkan mengubah nilai kunci utama.

Pemahaman saya selalu bahwa kunci utama harus tidak berubah, dan pencarian saya sejak membaca jawaban ini hanya memberikan jawaban yang mencerminkan hal yang sama dengan praktik terbaik.

Dalam keadaan apa nilai kunci primer perlu diubah setelah catatan dibuat?

5 dijejalkan
sumber
7
Kapan kunci utama dipilih yang tidak dapat diubah?
ypercubeᵀᴹ
2
Sejauh ini hanya sedikit nit untuk semua jawaban di bawah ini. Mengubah nilai dalam kunci utama tidak masalah besar kecuali jika kunci primer juga merupakan indeks berkerumun. Itu hanya benar-benar penting jika nilai indeks cluster berubah.
Kenneth Fisher
6
@KennethFisher atau jika direferensikan oleh satu (atau banyak) FK di tabel lain atau yang sama dan perubahan harus dilakukan ke banyak, (mungkin jutaan atau miliaran) baris.
ypercubeᵀᴹ
9
Tanyakan Skype. Ketika saya mendaftar beberapa tahun yang lalu, saya salah mengetik nama pengguna (meninggalkan surat dari nama belakang saya). Saya mencoba berkali-kali untuk memperbaikinya, tetapi mereka tidak dapat mengubahnya karena digunakan untuk kunci utama dan mereka tidak mendukung mengubahnya. Itu adalah contoh di mana pelanggan ingin kunci primer diubah, tetapi Skype tidak mendukungnya. Mereka dapat mendukung perubahan itu jika mereka ingin (atau mereka dapat membuat desain yang lebih baik), tetapi saat ini tidak ada yang memungkinkan. Jadi nama pengguna saya masih salah.
Aaron Bertrand
3
Semua nilai dunia nyata dapat berubah (untuk berbagai penyebab). Ini adalah salah satu motivasi asli untuk kunci pengganti / sintetis: untuk dapat menghasilkan nilai-nilai buatan yang dapat diandalkan untuk tidak pernah berubah.
RBarryYoung

Jawaban:

24

Jika Anda menggunakan nama seseorang sebagai kunci utama dan namanya berubah, Anda perlu mengubah kunci utama. Ini adalah apa ON UPDATE CASCADEyang digunakan untuk karena pada dasarnya Cascades perubahan ke semua tabel terkait yang memiliki hubungan asing kunci untuk kunci primer.

Sebagai contoh:

USE tempdb;
GO

CREATE TABLE dbo.People
(
    PersonKey VARCHAR(200) NOT NULL
        CONSTRAINT PK_People
        PRIMARY KEY CLUSTERED
    , BirthDate DATE NULL
) ON [PRIMARY];

CREATE TABLE dbo.PeopleAKA
(
    PersonAKAKey VARCHAR(200) NOT NULL
        CONSTRAINT PK_PeopleAKA
        PRIMARY KEY CLUSTERED
    , PersonKey VARCHAR(200) NOT NULL
        CONSTRAINT FK_PeopleAKA_People
        FOREIGN KEY REFERENCES dbo.People(PersonKey)
        ON UPDATE CASCADE
) ON [PRIMARY];

INSERT INTO dbo.People(PersonKey, BirthDate)
VALUES ('Joe Black', '1776-01-01');

INSERT INTO dbo.PeopleAKA(PersonAKAKey, PersonKey)
VALUES ('Death', 'Joe Black');

A SELECTterhadap kedua tabel:

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonKey = pa.PersonKey;

Pengembalian:

masukkan deskripsi gambar di sini

Jika kami memperbarui PersonKeykolom, dan jalankan kembali SELECT:

UPDATE dbo.People
SET PersonKey = 'Mr Joe Black'
WHERE PersonKey = 'Joe Black';

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonKey = pa.PersonKey;

kami melihat:

masukkan deskripsi gambar di sini

Melihat rencana UPDATEpernyataan di atas , kami melihat dengan jelas bahwa kedua tabel diperbarui oleh pernyataan pembaruan tunggal berdasarkan kunci asing yang didefinisikan sebagai ON UPDATE CASCADE:

masukkan deskripsi gambar di sini klik gambar di atas untuk melihatnya lebih jelas

Akhirnya, kami akan membersihkan tabel sementara kami:

DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;

1 cara yang disukai untuk melakukan ini menggunakan kunci pengganti adalah:

USE tempdb;
GO

CREATE TABLE dbo.People
(
    PersonID INT NOT NULL IDENTITY(1,1)
        CONSTRAINT PK_People
        PRIMARY KEY CLUSTERED
    , PersonName VARCHAR(200) NOT NULL
    , BirthDate DATE NULL
) ON [PRIMARY];

CREATE TABLE dbo.PeopleAKA
(
    PersonAKAID INT NOT NULL IDENTITY(1,1)
        CONSTRAINT PK_PeopleAKA
        PRIMARY KEY CLUSTERED
    , PersonAKAName VARCHAR(200) NOT NULL
    , PersonID INT NOT NULL
        CONSTRAINT FK_PeopleAKA_People
        FOREIGN KEY REFERENCES dbo.People(PersonID)
        ON UPDATE CASCADE
) ON [PRIMARY];

INSERT INTO dbo.People(PersonName, BirthDate)
VALUES ('Joe Black', '1776-01-01');

INSERT INTO dbo.PeopleAKA(PersonID, PersonAKAName)
VALUES (1, 'Death');

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonID = pa.PersonID;

UPDATE dbo.People
SET PersonName = 'Mr Joe Black'
WHERE PersonID = 1;

Untuk kelengkapan, rencana pernyataan pembaruan sangat sederhana, dan menunjukkan satu keuntungan untuk mengganti kunci, yaitu hanya satu baris yang perlu diperbarui dibandingkan dengan setiap baris yang berisi kunci dalam skenario kunci-alami:

masukkan deskripsi gambar di sini

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonID = pa.PersonID;

DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;

Output dari dua SELECTpernyataan di atas adalah:

masukkan deskripsi gambar di sini

Pada dasarnya, hasilnya hampir sama. Satu perbedaan utama adalah kunci alami lebar tidak diulang di setiap tabel di mana kunci asing terjadi. Dalam contoh saya, saya menggunakan VARCHAR(200)kolom untuk menyimpan nama orang tersebut, yang mengharuskan penggunaan di VARCHAR(200) mana - mana . Jika ada banyak baris dan banyak tabel yang berisi kunci asing, itu akan menambah banyak memori yang terbuang. Catatan, saya tidak berbicara tentang ruang disk yang terbuang karena kebanyakan orang mengatakan ruang disk sangat murah sehingga pada dasarnya gratis. Memori, bagaimanapun, mahal dan pantas untuk dihargai. Menggunakan integer 4-byte untuk kunci akan menghemat sejumlah besar memori ketika Anda mempertimbangkan panjang nama rata-rata sekitar 15 karakter.

Bersinggungan dengan pertanyaan tentang bagaimana dan mengapa kunci dapat berubah adalah pertanyaan tentang mengapa memilih kunci alami daripada kunci pengganti, yang merupakan pertanyaan yang menarik dan mungkin lebih penting, terutama di mana kinerja adalah tujuan desain. Lihat pertanyaan saya di sini tentang itu.


1 - http://weblogs.sqlteam.com/mladenp/archive/2009/10/06/Why-I-prefer-surrogate-keys-instead-of-natural-keys-in.aspx

Max Vernon
sumber
3
Untuk menghindari CASCADE (yang memiliki masalah dalam skenario tertentu) Anda juga bisa membuat kolom FK nullable, jadi jika Anda perlu mengubah PK, Anda dapat memperbarui baris terkait ke NULL (dalam potongan, jika ada banyak, atau berdasarkan tabel) , jika ada banyak tabel, atau keduanya), dan kemudian ubah nilai PK, lalu ubah lagi FK.
Aaron Bertrand
8

Meskipun Anda dapat menggunakan kunci yang alami dan / atau dapat berubah sebagai PK Anda, menurut pengalaman saya yang mengarah ke masalah, yang seringkali dapat dicegah dengan menggunakan PK yang memenuhi persyaratan ini:

 Guaranteed Unique, Always Exists, Immutable, and Concise.

Misalnya, banyak perusahaan di AS mencoba menggunakan Nomor Jaminan Sosial sebagai nomor ID pribadi, (dan PK) dalam sistem mereka. Kemudian mereka mengalami masalah berikut - kesalahan entri data yang mengarah ke beberapa catatan yang harus diperbaiki, orang-orang yang tidak memiliki SSN, orang-orang yang SSN-nya diubah oleh pemerintah, orang-orang yang memiliki duplikat SSN.

Saya sudah melihat semua skenario itu. Saya juga melihat perusahaan yang tidak ingin pelanggan mereka menjadi "hanya angka", yang berarti bahwa PK mereka akhirnya menjadi 'pertama + menengah + terakhir + DOB + zip' atau omong kosong serupa. Sementara mereka memang menambahkan cukup bidang untuk hampir menjamin keunikan, permintaan mereka sangat menghebohkan, dan memperbarui salah satu bidang itu berarti mengejar masalah konsistensi data.

Dalam pengalaman saya, PK yang dihasilkan oleh database itu sendiri hampir selalu merupakan solusi yang lebih baik.

Saya merekomendasikan artikel ini untuk petunjuk tambahan: http://www.agiledata.org/essays/keys.html

Byron Jones
sumber
6
Satu saran bagus dari artikel Scott Ambler yang dirujuk dalam jawaban Anda: "Beberapa orang akan memberi tahu Anda bahwa Anda harus selalu menggunakan kunci alami dan yang lain akan memberi tahu Anda bahwa Anda harus selalu menggunakan kunci pengganti. Orang-orang ini selalu terbukti salah, biasanya mereka melakukan sedikit lebih banyak daripada berbagi prasangka "agama data" mereka dengan Anda. Kenyataannya adalah bahwa kunci alami dan pengganti masing-masing memiliki kelebihan dan kekurangan masing-masing, dan bahwa tidak ada strategi yang sempurna untuk semua situasi. "
nvogel
7

Kunci utama dapat diubah ketika sinkronisasi dilakukan. Ini bisa menjadi kasus ketika Anda memiliki klien terputus dan menyinkronkan data dengan server pada interval tertentu.

Beberapa tahun yang lalu saya bekerja pada sistem di mana semua data acara pada mesin lokal memiliki Id baris negatif, seperti -1, -2, dll. Ketika data disinkronkan ke server, baris id pada server diterapkan ke klien. Katakanlah Id baris berikutnya pada server adalah 58. Lalu -1 akan menjadi 58, -2 59 dan seterusnya. Perubahan ID baris itu akan mengalir ke semua catatan FK anak pada mesin lokal. Mekanisme ini juga digunakan untuk menentukan catatan mana yang sebelumnya disinkronkan.

Saya tidak mengatakan ini adalah desain yang bagus, tetapi ini adalah contoh perubahan kunci primer dari waktu ke waktu.

Jon Raynor
sumber
5

Setiap desain yang melibatkan perubahan PRIMARY KEYsecara teratur adalah resep untuk bencana. Satu-satunya alasan bagus untuk mengubahnya adalah penggabungan dua database yang sebelumnya terpisah.

Seperti yang ditunjukkan oleh @MaxVernon perubahan sesekali dapat terjadi - kemudian gunakan ON UPDATE CASCADE, meskipun sebagian besar sistem saat ini menggunakan ID sebagai pengganti PRIMARY KEY.

Puritan seperti Joe Celko dan Fabian Pascal (situs yang layak diikuti) tidak setuju dengan penggunaan kunci pengganti, tapi saya pikir mereka telah kehilangan pertempuran khusus ini.

Vérace
sumber
3

Stabilitas adalah properti yang diinginkan untuk kunci tetapi itu adalah hal yang relatif dan bukan aturan absolut. Dalam praktiknya, sering berguna untuk mengubah nilai kunci. Dalam istilah relasional, data hanya dapat diidentifikasi dengan kunci (super) -nya. Ini mengikuti bahwa jika hanya ada satu kunci dalam tabel yang diberikan maka perbedaan antara A) mengubah nilai kunci, atau B) mengganti set baris dalam tabel dengan beberapa set baris yang sama atau berbeda yang berisi nilai kunci lainnya, pada dasarnya masalah semantik daripada logika.

Contoh yang lebih menarik adalah kasus tabel yang memiliki beberapa kunci di mana nilai-nilai dari satu atau lebih dari kunci tersebut mungkin harus berubah dalam kaitannya dengan nilai kunci lainnya. Ambil contoh tabel Karyawan dengan dua tombol: LoginName dan Nomor Lencana. Berikut ini contoh baris dari tabel itu:

+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZoeS     |47832   |
+---------+--------+

Jika ZoeS kehilangan lencananya maka mungkin dia dialokasikan yang baru dan mendapat nomor lencananya:

+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZoeS     |50282   |
+---------+--------+

Kemudian, dia mungkin memutuskan untuk mengubah nama loginnya:

+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZSmith   |50282   |
+---------+--------+

Kedua nilai kunci berubah - dalam kaitannya satu sama lain. Perhatikan bahwa itu tidak selalu membuat perbedaan mana yang dianggap "utama".

Dalam praktiknya "kekekalan", yaitu sama sekali tidak pernah mengubah nilai, tidak dapat diraih atau setidaknya tidak dapat diverifikasi. Sejauh perubahan membuat perbedaan sama sekali, jalan teraman mungkin adalah mengasumsikan bahwa kunci apa pun (atau atribut apa pun) mungkin perlu diubah.

nvogel
sumber
Saya menurunkan komentar Anda karena pernyataan berikut: "Dalam praktiknya" kekekalan ", yaitu sama sekali tidak pernah mengubah nilai, tidak dapat diraih atau setidaknya tidak mungkin untuk diverifikasi." Kekekalan IS mungkin, dan merupakan salah satu alasan terpenting untuk menggunakan kunci pengganti.
Byron Jones
3
Bagaimana Anda tahu bahwa seseorang tidak akan mengubah nilai kunci minggu depan atau dalam waktu 10 tahun? Anda mungkin berasumsi mereka tidak akan tetapi Anda tidak dapat secara realistis mencegah hal itu terjadi (jika Anda bertanggung jawab maka Anda dapat memasang penghalang untuk membuat orang lain tidak masuk dalam kekekalan, saya kira tetapi itu seperti kasus tepi). Yang benar-benar penting adalah bahwa perubahan sangat jarang terjadi, bukan karena itu tidak akan pernah terjadi.
nvogel
3

Cukup menarik, pertanyaan yang ditautkan tentang ROWGUID semacam menyediakan kasus penggunaannya sendiri: ketika Anda memiliki kunci utama yang bertentangan dalam database yang perlu disinkronkan. Jika Anda memiliki dua database yang perlu direkonsiliasi dan mereka menggunakan urutan untuk kunci utama, Anda ingin salah satu kunci untuk berubah sehingga tetap unik.

Di dunia yang ideal, ini tidak akan pernah terjadi. Anda akan menggunakan GUID untuk kunci utama untuk memulai. Namun, secara realistis, Anda mungkin bahkan tidak memiliki database terdistribusi saat mulai mendesain, dan mengonversinya menjadi GUID mungkin merupakan upaya yang diprioritaskan di bawah ini sehingga didistribusikan karena dianggap memiliki dampak yang lebih tinggi daripada menerapkan pembaruan kunci. Ini bisa terjadi jika Anda memiliki basis kode besar yang bergantung pada kunci integer dan akan memerlukan revisi besar untuk mengonversi ke GUID. Ada juga fakta bahwa GUID jarang (GUID yang tidak terlalu dekat satu sama lain, yang terjadi jika Anda membuatnya secara acak sebagaimana mestinya) dapat menyebabkan masalah untuk beberapa jenis indeks, juga, yang berarti Anda ingin menghindari penggunaan mereka sebagai kunci utama (disebutkan oleh Byron Jones ).

jpmc26
sumber
0

Satu skenario yang mungkin adalah katakanlah Anda memiliki afiliasi yang memiliki ID unik dan Anda tahu mereka tidak akan menduplikasi di afiliasi karena mereka memiliki karakter awal yang unik. Afiliasi memuat data ke tabel master. Ada catatan yang diproses dan kemudian diberikan ID master. Pengguna membutuhkan akses ke catatan segera setelah mereka dimuat walaupun mereka belum diproses. Anda ingin ID master didasarkan pada pesanan yang diproses dan Anda tidak akan selalu memproses dalam urutan catatan dimuat. Saya tahu sedikit dibuat-buat.

paparazzo
sumber
-1

Bayangkan situasi seperti ketika seseorang memilih Nomor Asuransi Nasional (NIN) sebagai Kunci Utama dan entah bagaimana seorang operator menyisipkan baris dengan NIN yang salah. Setelah memasukkan nilai, ada dua cara untuk memperbaiki kesalahan:

  1. Hapus catatan yang salah dan masukkan yang baru
  2. Perbarui nilainya ke yang benar dan gunakan Pada Pembaruan Kaskade jika ada batasan integritas referensial pada kolom itu
Behrouz Sameny
sumber