Menggunakan GUID sebagai Kunci Utama


32

Saya biasanya menggunakan ID kenaikan otomatis sebagai Kunci Utama dalam database. Saya mencoba mempelajari manfaat menggunakan GUID. Saya telah membaca artikel ini: https://betterexplained.com/articles/the-quick-guide-to-guids/

Saya menyadari bahwa GUID ini digunakan untuk mengidentifikasi objek di tingkat aplikasi. Apakah mereka juga disimpan sebagai kunci utama di tingkat basis data. Sebagai contoh, katakanlah saya memiliki kelas berikut:

public class Person
{
public GUID ID;
public string Name;
..

//Person Methods follow
}

Katakanlah saya ingin membuat orang baru di memori dan kemudian memasukkan Orang ke dalam basis data. Bisakah saya melakukan ini:

Person p1 = new Person();
p1.ID=GUID.NewGUID();
PersonRepository.Insert(p1);

Katakanlah saya memiliki database yang berisi jutaan dan jutaan baris dengan GUID sebagai Kunci Utama. Apakah ini akan selalu unik? Apakah saya bahkan memahami GUID dengan benar?

Saya membaca artikel ini sebelumnya: http://enterprisecraftsmanship.com/2014/11/15/cqs-with-database-generated-ids/ . Ini sedikit membingungkan saya karena tampaknya merekomendasikan media bahagia antara GUID dan integer sebagai Kunci Utama.

Edit 11/06/18

Saya percaya bahwa Guids lebih cocok daripada int untuk kebutuhan saya. Saya menggunakan CQRS lebih banyak hari ini dan GUID cocok lebih baik.

Saya memperhatikan bahwa beberapa pengembang memodelkan GUID sebagai string dalam model domain, misal di sini: https://github.com/dotnet-architecture/eShopOnContainers/blob/dev/src/Services/Ordering/Ordering.OrderingMomain/AggregatesModel/BuyerAggregate/ Buyer.cs - dalam kasus ini: IdentityGuid adalah GUID yang dimodelkan sebagai string. Apakah ada alasan untuk melakukan ini selain dari yang dinyatakan di sini: Gunakan objek nilai khusus atau Panduan sebagai pengidentifikasi entitas dalam sistem terdistribusi? . Apakah "normal" untuk memodelkan GUID sebagai string atau haruskah saya memodelkannya sebagai GUID dalam model dan basis data?



7
Tidak dijamin unik, meskipun kecil kemungkinan Anda akan melihat tabrakan. stackoverflow.com/questions/1155008/how-unique-is-uuid/…
icirellik

2
lihat juga: Tabrakan UUID
agas

2
Lihat juga dba.stackexchange.com/questions/54690/... , serta banyak pertanyaan lainnya - topik ini telah ditanyakan, dan dijawab, dan sering diperdebatkan.
Greenstone Walker

1
Sistem yang sedang saya kerjakan saat ini menggunakan UUID. Properti yang bagus adalah ID yang secara unik mengidentifikasi catatan, bukan ID berurutan yang mengidentifikasi catatan dalam tabel itu.
Justin

Jawaban:


41

GUID menurut definisi "IDentifiers Global yang Unik". Ada konsep serupa tetapi sedikit berbeda di Jawa yang disebut UUID "Universally Unique IDentifiers". Nama-nama tersebut dapat dipertukarkan untuk semua penggunaan praktis.

GUID adalah pusat bagaimana Microsoft membayangkan pengelompokan basis data untuk bekerja, dan jika Anda perlu memasukkan data dari sumber yang terkadang terhubung, mereka benar-benar membantu mencegah tabrakan data.

Beberapa Fakta Pro-GUID:

  • GUID mencegah tabrakan kunci
  • GUID membantu menggabungkan data antara jaringan, mesin, dll.
  • SQL Server memiliki dukungan untuk GUIDS semi-sekuensial untuk membantu meminimalkan fragmentasi indeks ( ref , beberapa peringatan)

Beberapa Ugeness dengan GUIDs

  • Mereka besar, masing-masing 16 byte
  • Mereka rusak, jadi Anda tidak dapat mengurutkan pada ID dan berharap untuk mendapatkan urutan penyisipan seperti yang Anda bisa pada id penambahan otomatis
  • Mereka lebih rumit untuk bekerja dengan, terutama pada set data kecil (seperti melihat-lihat tabel)
  • Implementasi GUID baru lebih kuat pada SQL Server daripada di C # library (Anda dapat memiliki GUIDS berurutan dari SQL Server, di C # itu acak)

GUID akan membuat indeks Anda lebih besar, sehingga biaya ruang disk untuk mengindeks kolom akan lebih tinggi. GUID acak akan memecah indeks Anda.

Jika Anda tahu Anda tidak akan menyinkronkan data dari jaringan yang berbeda, GUID dapat membawa lebih banyak overhead daripada nilainya.

Jika Anda memiliki kebutuhan untuk menelan data dari klien yang terkadang terhubung, mereka bisa menjadi jauh lebih kuat untuk mencegah tabrakan kunci daripada mengandalkan pengaturan rentang urutan untuk klien tersebut.


18
Pemahaman saya adalah bahwa GUID identik dengan UUID. UUID adalah nama standar. GUID adalah apa yang Microsoft ciptakan sebelum RFC 4122 .
JimmyJames

13
"Mereka rusak, jadi kamu tidak bisa mengurutkan ID dan berharap mendapatkan urutan penyisipan seperti kamu bisa pada id kenaikan otomatis" Terus terang, aku juga tidak nyaman mengandalkan itu dengan id reguler juga. Meskipun mungkin dalam kasus tepi ekstrem untuk id yang lebih rendah untuk dikomit ke disk nanti, saya lebih suka mengandalkan data pengurutan yang berguna, seperti cap waktu penyisipan. Id harus diperlakukan seperti alamat memori - semuanya memiliki satu, tetapi nilainya sendiri tidak ada artinya. Gunakan paling banyak untuk tiebreak. Terutama karena jika Anda memiliki beban massal, pesanan penyisipan tidak dijamin.
Clockwork-Muse

8
@CortAmmon Menurut Wikipedia dan RFC 4122 , keduanya identik. P. Leach dari Microsoft adalah salah satu pencipta RFC. Saya pikir sejak RFC dibuat, keduanya sama. Dari RFC: "UUID (Pengidentifikasi Unik Universal), juga dikenal sebagai GUID (Pengidentifikasi Unik Global)." Saya pikir ini juga berguna untuk mencatat bahwa GUID tidak dibuat oleh MS. Mereka baru saja menciptakan nama baru untuk teknologi yang diadopsi dari tempat lain.
JimmyJames

6
"SQL Server memiliki optimisasi untuk berurusan dengan GUID sehingga tidak terlalu memengaruhi kinerja kueri." -1 Hampir tidak cukup optimal. Saya bekerja dengan DB di mana semua PK adalah penuntun, dan salah satu penyebab utama kinerja yang buruk.
Andy

7
"SQL Server memiliki optimisasi untuk berurusan dengan GUID sehingga tidak terlalu memengaruhi kinerja kueri. " Tidak benar. Pernyataan itu mengasumsikan tipe data lain tidak dioptimalkan. Server database juga memiliki optimasi untuk berurusan dengan nilai int sederhana, misalnya. GUID / UUID jauh lebih lambat daripada menggunakan nilai int 4-byte. 16 byte tidak akan pernah secepat 4 byte - terutama pada mesin yang menangani paling banyak 4 atau 8 byte secara asli.
Andrew Henle

28

Apakah ini akan selalu unik?

Selalu? tidak, tidak selalu; ini adalah urutan bit yang terbatas.

Katakanlah saya memiliki database yang berisi jutaan dan jutaan baris dengan GUID sebagai Kunci Utama.

Jutaan dan jutaan, Anda mungkin aman. Jutaan juta, dan kemungkinan tabrakan menjadi signifikan. Namun ada kabar baik: Anda sudah kehabisan ruang disk saat itu terjadi.

Bisakah saya melakukan ini?

Kamu bisa; itu bukan ide yang sepenuhnya bagus. Model domain Anda biasanya tidak menghasilkan angka acak; mereka harus menjadi input untuk model Anda.

Selain itu, ketika Anda berurusan dengan jaringan yang tidak dapat diandalkan, di mana Anda mungkin mendapatkan pesan duplikat, UUID yang dihasilkan secara deterministik akan melindungi Anda dari memiliki entitas duplikat. Tetapi jika Anda menetapkan nomor acak baru untuk masing-masing, maka Anda memiliki lebih banyak pekerjaan yang harus dilakukan untuk mengidentifikasi duplikasi.

Lihat deskripsi uuid berbasis nama di RFC 4122

Apakah "normal" untuk memodelkan GUID sebagai string atau haruskah saya memodelkannya sebagai GUID dalam model dan basis data?

Saya tidak berpikir itu sangat berarti. Untuk sebagian besar model domain Anda, ini adalah pengidentifikasi ; satu-satunya pertanyaan yang Anda minta adalah apakah itu sama atau tidak dengan beberapa pengenal lainnya. Model domain Anda biasanya tidak akan melihat representasi memori dari pengidentifikasi.

Jika GUID tersedia sebagai "tipe primitif" di pengaturan agnostik domain Anda, saya akan menggunakannya; itu memungkinkan konteks pendukung untuk memilih optimasi yang sesuai yang mungkin tersedia.

Apa yang harus Anda kenali, bagaimanapun, adalah bahwa representasi pengidentifikasi, baik dalam memori maupun dalam penyimpanan, adalah keputusan yang Anda buat dalam implementasi Anda, dan oleh karena itu Anda harus mengambil langkah-langkah untuk memastikan bahwa cetak kaki kode digabungkan dengan keputusannya kecil - lihat Parnas 1972 .


20
+1 untuk "Anda sudah kehabisan ruang disk pada saat itu terjadi."
w0051977

2
Saya merasa konsep " UUID yang dihasilkan secara deterministik " sangat penting (lihat Data Vault 2)
alk

Memang, Mampu menghitung kembali UUID / GUID berdasarkan data lain adalah sangat membantu, terutama untuk mendeteksi duplikat. Saya pernah membangun sistem pemrosesan pesan yang menyimpan pesan-pesan itu dan mendorongnya melalui pipa pemrosesan. Saya membuat hash pesan dan menggunakannya sebagai kunci utama di seluruh sistem. Hanya saja, dalam dan dari dirinya sendiri, memecahkan saya BANYAK masalah untuk mengidentifikasi pesan ketika kami harus skala.
Newtopian

Jutaan juta = 2 ^ 40. Itu membuat 2 ^ 79 pasang kemungkinan tabrakan. GUID memiliki 2 ^ 128 bit, jadi peluangnya adalah satu dari 2 ^ 49. Ini jauh lebih mungkin bahwa Anda memiliki bug yang menggunakan kembali GUID yang sama untuk dua catatan, atau yang secara keliru percaya ada tabrakan di mana tidak ada.
gnasher729

Saya akan kembali melalui pertanyaan bersejarah saya. Sebelum saya menerima; dapatkah Anda melihat hasil edit saya?
w0051977

11

GUID atau UUID kemungkinan besar akan unik karena bagaimana mereka dihasilkan dan mereka menyediakan cara yang aman untuk menjamin keunikan tanpa harus berkomunikasi dengan otoritas pusat.

Manfaat GUID sebagai Kunci Utama:

  • Anda dapat menyalin data di antara berbagai pecahan gugus dan tidak perlu khawatir tentang tabrakan PK.
  • Ini memungkinkan Anda untuk mengetahui kunci utama Anda sebelum Anda memasukkan catatan apa pun.
  • Menyederhanakan logika transaksi untuk menyisipkan catatan anak.
  • Tidak mudah ditebak.

Dalam contoh yang Anda berikan:

Person p1 = new Person();
p1.ID = GUID.NewGUID();
PersonRepository.Insert(p1);

Menentukan GUID sebelum waktu penyisipan dapat menyimpan perjalanan pulang-pergi ke basis data ketika memasukkan catatan anak berturut-turut dan memungkinkan Anda untuk mengikatnya dalam transaksi yang sama.

Person p2 = new Person();
p2.ParentID = p1.ID
PersonRepository.Insert(p2);

Kerugian pada GUID sebagai Kunci Utama:

  • Mereka berukuran 16 byte besar yang berarti mereka akan mengkonsumsi lebih banyak ruang karena indeks dan kunci asing ditambahkan.
  • Mereka tidak mengurutkan dengan baik karena mereka pada dasarnya angka acak.
  • Penggunaan indeks sangat, sangat, sangat buruk.
  • Banyak daun bergerak.
  • Mereka sulit diingat.
  • Mereka sulit diucapkan.
  • Mereka dapat membuat URL lebih sulit dibaca.

Jika aplikasi Anda tidak memerlukan sharding atau clustering, akan lebih baik untuk tetap menggunakan tipe data yang lebih kecil dan lebih sederhana seperti int atau bigint.

Banyak basis data memiliki implementasi internal mereka sendiri yang berupaya untuk mengurangi masalah penyimpanan yang disebabkan oleh GUID dan SQL Server bahkan memiliki fungsi newitialentialid untuk membantu pemesanan UUID yang memungkinkan penggunaan indeks yang lebih baik dan mereka umumnya memiliki karakteristik kinerja yang lebih baik.

Selain itu, dari perspektif penguji, pengguna, atau pengembang yang bekerja dengan aplikasi, menggunakan ID melalui GUID akan secara signifikan meningkatkan komunikasi. Bayangkan harus membaca GUID melalui telepon.

Pada akhirnya, kecuali pengelompokan skala besar atau URL yang mengaburkan merupakan persyaratan, lebih pragmatis untuk tetap menggunakan ID peningkatan-otomatis.


1
Satu hal yang perlu dipertimbangkan adalah bahwa tergantung pada jenis UUID , mereka berisi informasi yang berpotensi digunakan untuk mengidentifikasi mesin tempat mereka dihasilkan. Varian acak murni mungkin lebih mungkin bertabrakan tanpa entropi yang cukup. Ini harus dipertimbangkan sebelum digunakan dalam URI.
JimmyJames

Setuju, meskipun seseorang tidak boleh membuka kunci utama mereka dalam URL. Beberapa metode yang lebih tepat harus digunakan untuk memastikan bahwa tidak ada data yang aman bocor ke system.s eksternal
icirellik

1
Ada satu lagi kasus penggunaan: memasukkan database OLTP berat di mana penguncian untuk urutan adalah hambatan. Menurut teman DBA Oracle saya, ini tidak jarang terdengar, Anda bahkan tidak perlu skala besar atau cluster untuk itu. • Pada akhirnya, pertimbangkan pro dan kontra (dan jangan bingung pro / kontra UUID dengan pro / kontra yang tidak spesifik untuk UUID seperti yang dilakukan beberapa poster) dan ukur .
mirabilos

1
Jika Anda menggunakan newafterentialid maka Anda harus pergi ke db untuk mendapatkan id (seperti dengan int identitas), bukan? Apa manfaatnya di sini.
w0051977

1
@mirabilos Untuk menjadi jelas, ketika saya mengatakan mengerikan kami akhirnya memiliki sisipan yang mengambil menit per baris. Ini dimulai dengan baik, tetapi setelah ada 10 dari ribuan baris, itu berjalan sangat cepat. Jika tidak jelas, 10s dari ribuan baris adalah tabel yang sangat kecil.
JimmyJames

4

Saya akan mengatakan tidak, jangan gunakan GUID sebagai kunci utama. Saya sebenarnya berurusan dengan DB seperti itu sekarang, dan mereka adalah salah satu penyebab utama masalah kinerja.

12 byte tambahan bertambah dengan cepat; ingat, sebagian besar PK akan menjadi FK di tabel lain, dan hanya tiga FK dalam sebuah tabel, Anda sekarang memiliki 48 byte tambahan untuk setiap baris. Itu bertambah dalam tabel dan indeks. Itu juga bertambah di disk I / O. 12 byte tambahan itu perlu dibaca dan ditulis.

Dan jika Anda tidak menggunakan pengurutan berurutan dan PK dikelompokkan (yang adalah apa yang terjadi secara default), SQL dari waktu ke waktu harus memindahkan seluruh halaman data untuk memeras lebih banyak ke "tempat" yang tepat. Untuk basis data transaksi yang sangat tinggi dengan banyak sisipan, pembaruan, dan penghapusan, segala sesuatunya cepat rusak.

Jika Anda memerlukan semacam pengidentifikasi unik untuk sinkronisasi atau semacamnya, tambahkan kolom panduan. Hanya saja, jangan menjadikannya PK.


4
Person p1 = new Person();
p1.ID=GUID.NewGUID();
PersonRepository.Insert(p1);

Sejauh ini inilah alasan paling penting untuk menggunakan GUID.

Fakta bahwa Anda dapat membuat id unik tanpa kode Anda mengetahui atau berkomunikasi dengan lapisan kegigihan Anda adalah manfaat besar.

Anda dapat yakin bahwa objek Orang yang baru saja Anda buat di server, telepon pc, laptop, perangkat offline atau apa pun yang unik di semua server Anda di seluruh dunia yang didistribusikan.

Anda dapat menempelkannya dalam segala jenis basis data rdb atau no-sql, kirim, kirim ke layanan web apa pun atau buang segera setelah tidak dibutuhkan

Tidak, Anda tidak akan pernah mendapatkan tabrakan.

Ya, sisipan dapat sedikit lebih lambat karena indeks mungkin perlu dipikirkan.

Ya itu lebih besar dari int.

  • sunting. harus menembak sebelum menyelesaikan.

Saya tahu banyak orang merasa kuat tentang int masuk otomatis dan ini adalah topik kontroversial dengan DBA

Tapi aku benar-benar tidak bisa menyatakan dengan sangat kuat betapa hebatnya guids. Anda harus menggunakan panduan secara default di aplikasi apa pun.

int otomatis memiliki banyak banyak kekurangan

  • Anda menggunakan db No-Sql terdistribusi. Anda tidak bisa berbicara dengan semua contoh lain untuk mencari tahu apa nomor berikutnya.

  • Anda menggunakan sistem antrian pesan. Hal-hal perlu ID sebelum mereka mencapai db

  • Anda membuat beberapa item dan mengeditnya sebelum menyimpan. Setiap kebutuhan id sebelum Anda menekan db

  • Anda ingin menghapus dan memasukkan kembali baris. Pastikan Anda tidak menghitung jumlah tawaran otomatis dan kehabisan!

  • Anda ingin tidak mengekspos berapa banyak Pesanan yang telah Anda ambil tahun ini untuk setiap pengguna

  • Anda ingin memindahkan data yang dianonimkan dari produksi untuk menguji dan menjaga hubungan tetap utuh. Namun tidak menghapus semua data uji yang ada.

  • Anda ingin menggabungkan produk penyewa tunggal Anda ke dalam basis data multi penyewa tetapi setiap orang memiliki pesanan 56.

  • Anda membuat objek yang bertahan tapi fana. (pesanan tidak lengkap) lagi, jangan gunakan semua int Anda dengan hal-hal yang tidak ada lagi.

Daftar ini tidak ada habisnya dan semuanya adalah masalah nyata yang terjadi pada orang setiap saat. tidak seperti kehabisan ruang disk karena cols FK sedikit lebih besar

Akhirnya masalah besar dengan int adalah Anda kehabisan !!! ok secara teori Anda tidak, ada banyak. Namun dalam praktiknya Anda melakukannya karena orang tidak memperlakukannya seperti angka acak tanpa makna. mereka melakukan hal-hal seperti

  • oh saya tidak ingin pelanggan berpikir kami baru. mulai dari 10.000

  • Saya harus mengimpor banyak data jadi saya hanya menaikkan seed menjadi 1m sehingga kami tahu apa yang diimpor

  • kita membutuhkan kategori data. setiap periode dimulai pada jutaan berikutnya sehingga kita dapat menggunakan angka pertama sebagai angka ajaib

  • Saya menghapus dan mengimpor kembali semua data lagi dengan id baru. Ya, bahkan log audit.

  • gunakan nomor ini, yang merupakan kunci komposit, sebagai id dari hal lain ini


1
Tidak ada yang salah secara faktual dengan jawaban ini, tapi saya akan (untuk menangkal downvotes lebih lanjut) mungkin membuat eksplisit peringatan bahwa meskipun aplikasi kehidupan nyata tidak akan mengalami tabrakan, secara teori itu mungkin. (Atau mungkin 45+ database exabyte lebih lazim daripada yang saya kira ...). Meskipun saya pikir bahasa "alasan paling penting" agak kuat, inilah yang menurut saya paling berguna.
BurnsBA

2
itu lebih mungkin bahwa sebuah int mobil akan bertabrakan dari seorang penuntun
Ewan

4
-1 untuk "Anda harus menggunakan panduan secara default di aplikasi apa pun." Itu Tergantung ™. Dan seperti yang ditunjukkan orang lain, GUID / UUID, sama sekali tidak dijamin unik.
Max Vernon

3
Jawaban "Itu tergantung" tidak berguna, tentu akan ada beberapa aplikasi aneh di mana int lebih baik. Tetapi kemungkinan aplikasi Anda bukan salah satunya. GUID adalah hal paling unik yang bisa Anda dapatkan
Ewan

2
Saya pikir akan ada beberapa aplikasi aneh di mana panduan lebih baik. Unik bukan hal yang paling penting untuk dipertimbangkan. "Kelemahan" int Anda secara besar-besaran berlebihan, dan Anda tidak mempertimbangkan salah satu dari banyak kelemahan dari panduan.
Andy

2

Saya menyadari bahwa GUID ini digunakan untuk mengidentifikasi objek di tingkat aplikasi. Apakah mereka juga disimpan sebagai kunci utama di tingkat basis data.

Di situlah Anda harus berhenti, di sana, dan memikirkan kembali.

Kunci utama basis data Anda TIDAK PERNAH memiliki arti bisnis. Seharusnya tidak ada artinya menurut definisi.

Jadi tambahkan GUID sebagai kunci bisnis Anda, dan kunci primer normal (biasanya int panjang) sebagai kunci primer basis data. Anda selalu dapat menempatkan indeks unik pada GUID untuk memastikan keunikan.

Itu berbicara teori database tentu saja, tapi itu praktik yang baik juga. Saya telah berurusan dengan basis data di mana kunci utama memiliki makna bisnis (satu pelanggan berpikir untuk menghemat beberapa sumber daya basis data dengan menggunakannya sebagai nomor karyawan, nomor pelanggan, dll. Misalnya) dan selalu menyebabkan masalah.


1
Bagaimana ini berbeda dari permintaan dari lapisan aplikasi menggunakan kunci primer integer? Pada titik itu, itu juga sedang digunakan untuk mengidentifikasi objek pada lapisan aplikasi. Anda perlu cara untuk mengidentifikasi objek dalam database dari lapisan aplikasi.
icirellik

@icirellik kunci utama dimaksudkan untuk penggunaan internal oleh database, untuk menautkan catatan induk dan anak dan sejenisnya. Ini TIDAK dimaksudkan untuk digunakan oleh logika aplikasi, Anda menggunakan ID bisnis untuk itu, seperti nomor atau nama produk.
jwenting

2

Selalu gunakan basis data yang dihasilkan, Kunci Utama (PK) peningkatan otomatis.

Mengapa menggunakan penambahan otomatis alih-alih GUID / UUID?

  • GUID (UUID) tidak mencegah tabrakan kunci karena tidak unik dan tidak ada cara untuk membuatnya unik karena dihasilkan dari berbagai sumber.
  • GUID tidak membantu penggabungan karena mereka sangat meningkatkan proses penggabungan yang sudah memakan waktu dengan kolom PK dan FK yang sangat panjang dan non-integer yang membutuhkan banyak waktu untuk diproses. Ingat bahwa untuk sebagian besar PK, akan ada setidaknya 1 meja lainnya dengan setidaknya 2 kunci dengan ukuran yang sama: itu adalah PK sendiri dan satu FK kembali ke tabel pertama. Semua harus diselesaikan dalam gabungan.

Tetapi bagaimana cara menangani pecahan, kelompok, dll.?

  • Buat PK multi-kolom yang terdiri dari kolom terpisah yang mengidentifikasi setiap shard / cluster / database / apa pun yang mengelola sendiri kunci peningkatan otomatis itu sendiri. Sebagai contoh...

PK 3 kolom untuk tabel berkerumun mungkin ...

 DB | SH | KEY     |
----|----|---------|
 01 | 01 | 1234567 |

Tapi bagaimana dengan ...?

  • Banyak perjalanan ke basis data - Sebagian besar aplikasi tidak perlu secara unik mengidentifikasi catatan yang dibuat sampai dimasukkan ke dalam basis data sejak utas / sesi / apa pun itu hanya bekerja satu per satu. Jika aplikasi benar-benar membutuhkan kemampuan ini, gunakan aplikasi PK sementara yang dihasilkan yang tidak dikirim ke database . Biarkan database kemudian menempatkan PK kenaikan otomatis sendiri di baris saat dimasukkan. Sisipan akan menggunakan PK sementara, sementara pembaruan dan penghapusan akan menggunakan PK permanen yang ditugaskan oleh database.

  • Kinerja - Komputer dapat memproses bilangan bulat sederhana jauh lebih cepat dari yang lain karena domain yang jauh lebih besar jika nilai per elemen dalam GUID (37) vs. integer (10). Ingat juga bahwa setiap karakter dalam GUID harus dikonversi terlebih dahulu menjadi angka yang akan dimanipulasi oleh CPU.

Penyalahgunaan Umum Kunci Utama PK hanya memiliki satu tujuan ... untuk mengidentifikasi baris dalam tabel secara unik. Yang lainnya adalah penyalahgunaan yang terlalu umum.

Mendeteksi Catatan yang Hilang

  • Catatan yang hilang tidak dapat dideteksi dengan melihat PK. Memberkati QA untuk setidaknya berusaha memastikan kualitas data. Namun, mereka dan kurangnya pemahaman programmer tentang bagaimana kunci dalam sistem database modern ditugaskan sering membawa mereka ke ketidakpercayaan bahwa angka yang hilang dalam PK yang bertambah secara otomatis berarti data yang hilang. Itu bukan karena ...
  • Untuk kinerja, sistem database mengalokasikan blok angka dalam 'urutan' (batch, rentang) untuk meminimalkan perjalanan ke database aktual dalam penyimpanan. Ukuran urutan angka-angka ini sering di bawah kendali DBA tetapi mungkin tidak dapat disesuaikan berdasarkan tabel.
  • Kuncinya adalah ... nomor yang tidak digunakan dari urutan ini tidak pernah dikembalikan ke database sehingga selalu ada kesenjangan dalam angka PK.
  • Mengapa ada nomor yang tidak digunakan yang Anda minta? Karena berbagai tindakan pemeliharaan database dapat menyebabkan urutan ditinggalkan. Ini adalah hal-hal seperti restart, sebagian besar memuat ulang tabel, beberapa jenis pemulihan dari cadangan dan beberapa operasi lainnya.

Penyortiran

  • Penyortiran berdasarkan PK sangat rawan kesalahan karena kebanyakan orang akan berpikir itu mencantumkan baris dalam urutan mereka dibuat dan yang sesuai dengan waktu jam. Sebagian besar, tetapi tidak perlu.
  • Mesin database dioptimalkan untuk kinerja maksimum dan itu bisa berarti menunda memasukkan hasil dari transaksi rumit yang sudah berjalan lama untuk memasukkan yang pendek sederhana, "out-of-turn" untuk berbicara.

Apa pendapat Anda tentang skema tabel sehingga satu-satunya kolom unik adalah kunci primer penambahan-otomatis yang dibuat-database? Khususnya untuk tabel yang tidak memiliki kunci asing tetapi kunci utama siapa yang merupakan kunci asing untuk beberapa tabel terkait?
RibaldEddie

Saya telah menambahkan lebih banyak jawaban di sepanjang baris itu. Jawaban asli tidak lengkap karena aplikasi Android SE yang saya tunggu. Saya pikir penulisan ulang utama aplikasi sedang dalam pengembangan.
DocSalvager

Jadi menurut Anda, tidak masalah jika tabel berisi sejumlah baris yang identik, simpan untuk kunci primer penambahan-otomatisnya?
RibaldEddie

@RibaldEddie - Sejauh apa DB dirancang untuk memungkinkan ... benar-benar. Penghapusan itu mudah. Ketika skenario Anda terjadi, saya akan menganggapnya sebagai bug yang harus diperbaiki dalam perangkat lunak dan kemudian menghapus salah satu baris. Kasus yang jauh lebih umum adalah dua catatan untuk hal yang sama dengan data yang sedikit berbeda sehingga harus digabungkan. Jika sebuah kolom kosong di satu catatan dan memiliki nilai di yang lain, pilihannya jelas dan bisa otomatis. Seringkali datetimestamp dapat digunakan untuk menengahi penggabungan otomatis. Beberapa duplikat mengharuskan seseorang untuk menyelesaikan dan memverifikasi penggabungan berdasarkan aturan bisnis.
DocSalvager

1

Seperti apa pun, ada kelebihan dan kekurangan untuk melakukan ini:

Yang baik:

  1. Panjang kunci Anda selalu sama (basis data sangat besar dapat memiliki kunci sangat besar)

  2. Keunikan dijamin cukup banyak - bahkan ketika Anda membuatnya dari sistem yang terpisah, dan / atau belum membaca ID terakhir dari database

Keburukan:

  1. Seperti yang disebutkan banyak di atas - indeks yang lebih besar dan penyimpanan data.

  2. Anda tidak dapat memesan dengan ID, Anda harus memesan dengan sesuatu yang lain. Lebih banyak indeks, mungkin kurang efisien.

  3. Mereka kurang dapat dibaca manusia. Bilangan bulat biasanya lebih mudah diurai, diingat, dan diketik untuk orang. Menggunakan GUIDs sebagai ID dalam klausa WHERE di beberapa tabel yang digabungkan dapat membuat kepala Anda meleleh.

Seperti halnya segala sesuatu, gunakan sesuai kebutuhan, jangan dogmatis - dalam banyak situasi bilangan bulat yang bertambah secara otomatis lebih baik, kadang-kadang GUID hebat.


0

Ya, Anda dapat menggunakan GUID sebagai kunci utama. Sisi bawah adalah ukuran dan fragmentasi indeks yang cepat.

Kecuali jika Anda memerlukan keunikan di seluruh basis data (misalnya kluster) lebih disukai.


Generator GUID dapat menghasilkan GUID yang sama lebih dari sekali, di situlah letak kelemahannya. Apakah mereka mau atau tidak tergantung pada perinciannya, terutama pada interval antara clock tick. Misalnya generator berbasis jam hanya dapat mencentang setiap 100 ms, mengarah ke 2 GUID yang diminta dalam 100 ms pada mesin yang identik. Ada cara untuk menghindari itu, sebagian besar, tetapi banyak generator GUID bekerja sepenuhnya dari alamat IP dan / atau alamat MAC dan cap waktu.
jwenting

0

Inilah pendapat saya tentang masalah ini - solusinya adalah setengah jalan antara nilai-nilai GUID dan int, mengambil yang terbaik dari keduanya.

Kelas menghasilkan nilai Id pseudo acak (tetapi meningkat seiring waktu), yang mirip dengan GUID Comb .

Keuntungan utama adalah bahwa hal itu memungkinkan nilai Id dihasilkan pada klien, daripada menggunakan nilai kenaikan otomatis yang dihasilkan pada server (yang membutuhkan perjalanan bolak-balik) dengan risiko hampir nol dari nilai duplikat.

Nilai yang dihasilkan hanya menggunakan 8 byte daripada 16 untuk GUID, dan tidak bergantung pada satu urutan pengurutan database tertentu (misalnya Sql Server untuk GUID ). Nilai-nilai dapat diperluas untuk menggunakan seluruh jangka panjang yang tidak ditandatangani, tetapi ini akan menyebabkan masalah dengan basis data atau penyimpanan data lainnya yang hanya memiliki tipe bilangan bulat yang ditandatangani.

public static class LongIdGenerator
{
    // set the start date to an appropriate value for your implementation 
    // DO NOT change this once any application that uses this functionality is live, otherwise existing Id values will lose their implied date
    private static readonly DateTime PeriodStartDate = new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    private static readonly DateTime PeriodEndDate = PeriodStartDate.AddYears(100);
    private static readonly long PeriodStartTicks = PeriodStartDate.Ticks;
    private static readonly long PeriodEndTicks = PeriodEndDate.Ticks;
    private static readonly long TotalPeriodTicks = PeriodEndTicks - PeriodStartTicks;

    // ensures that generated Ids are always positve
    private const long SEQUENCE_PART_PERMUTATIONS = 0x7FFFFFFFFFFF; 

    private static readonly Random Random = new Random();

    private static readonly object Lock = new object();
    private static long _lastSequencePart;

    public static long GetNewId()
    {
        var sequencePart = GetSequenceValueForDateTime(DateTime.UtcNow);

        // extra check, just in case we manage to call GetNewId() twice before enough ticks have passed to increment the sequence 
        lock (Lock)
        {
            if (sequencePart <= _lastSequencePart)
                sequencePart = _lastSequencePart + 1;

            _lastSequencePart = sequencePart;
        }

        // shift so that the sequence part fills the most significant 6 bytes of the result value
        sequencePart = (sequencePart << 16);

        // randomize the lowest 2 bytes of the result, just in case two different client PCs call GetNewId() at exactly the same time
        var randomPart = Random.Next() & 0xFFFF;

        return sequencePart + randomPart;
    }

    // used if you want to generate an Id value for a historic time point (within the start and end dates)
    // there are no checks, compared to calls to GetNewId(), but the chances of colliding values are still almost zero
    public static long GetIdForDateTime(DateTime dt)
    {
        if (dt < PeriodStartDate || dt > PeriodStartDate)
            throw new ArgumentException($"value must be in the range {PeriodStartDate:dd MMM yyyy} - {PeriodEndDate:dd MMM yyyy}");

        var sequencePart = GetSequenceValueForDateTime(dt.ToUniversalTime());
        var randomPart = Random.Next() & 0xFFFF;
        return ( sequencePart << 16 ) + randomPart;
    }

    // Get a 6 byte sequence value from the specified date time - startDate => 0 --> endDate => 0x7FFFFFFFFFFF
    // For a 100 year time period, 1 unit of the sequence corresponds to about 0.022 ms
    private static long GetSequenceValueForDateTime(DateTime dt)
    {
        var ticksFromStart = dt.ToUniversalTime().Ticks - PeriodStartTicks;
        var proportionOfPeriod = (decimal)ticksFromStart / TotalPeriodTicks;
        var result = proportionOfPeriod * SEQUENCE_PART_PERMUTATIONS;
        return (long)result;
    }

    public static DateTime GetDateTimeForId(long value)
    {
        // strip off the random part - the two lowest bytes
        var timePart = value >> 16;
        var proportionOfTotalPeriod = (decimal) timePart / SEQUENCE_PART_PERMUTATIONS;
        var ticks = (long)(proportionOfTotalPeriod * TotalPeriodTicks);
        var result = PeriodStartDate.AddTicks(ticks);
        return result;
    }
}
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.