Haruskah saya menambahkan bidang penambahan otomatis / IDENTITAS ke tabel referensi silang hanya untuk tujuan PK?

9

Saya menambahkan tabel referensi silang berikut ke DB yang di-hosting oleh SQL Server:

company_id bigint not null (FK)
org_path nvarchar (2048) not null

The company_idlapangan mengacu pada idlapangan di meja lain (di mana itu kunci utama).

Mengingat bahwa ada juga beberapa catatan dengan yang sama company_id, kunci primer apa pun harus menggunakan kedua bidang. Namun, saya tidak dapat membuat kunci menggunakan kedua bidang karena org_pathterlalu panjang untuk SQL Server.

Adapun org_path, ini adalah satu-satunya tabel yang ada. Ada kemungkinan bahwa permintaan ke tabel ini akan meminta semua entri atau semua org_pathentri company_id. Atau dengan kata lain, tampak meragukan bahwa tabel ini akan pernah ditanyakan org_path. Lebih jauh lagi, itu tidak mungkin bahwa org_pathakan diperbarui, dan lebih mungkin dimasukkan dan - mungkin jarang - dihapus.

Saya berharap bahwa jumlah total baris akan menjadi ribuan rendah.

Juga, alasannya nvarchar (2048)adalah karena nilainya harus meniru bahwa dalam DB pihak ketiga. Contoh tipikal adalah sesuatu seperti

\Translation Providers\[customer name]\[order name]\

dan dapat berisi diakritik.

Jadi pertanyaan saya adalah ini: apakah akan lebih efisien untuk menambahkan idbidang kenaikan-otomatis dan menggunakannya bersamaan dengan company_idsebagai kunci utama, atau apakah akan menambahkan overhead yang tidak perlu - dan apakah fakta bahwa company_idkunci utama di tabel lain memiliki efek di sini?

awj
sumber

Jawaban:

7

Untuk indeks cluster yang tidak unik comany_idsendirian, SQL Server akan secara otomatis menambahkan integer integer 4 byte ke semua duplikat (yaitu yang kedua dan selanjutnya untuk nilai kunci) kunci indeks yang dikelompokkan untuk membuatnya unik. Ini tidak terpapar ke pengguna sekalipun.

Keuntungan menambahkan pengidentifikasi unik Anda sendiri sebagai kolom kunci sekunder adalah bahwa Anda masih dapat mencari dengan company_idtetapi juga mencari baris individual secara lebih efisien (menggunakan company_id, identitycoldaripada menggunakan company_idpredikat residu aktif org_path). Indeks berkerumun kemudian akan menjadi unik company_id, identitycol, sehingga tidak ada pengunsi tersembunyi yang akan ditambahkan.

Juga, jika Anda berakhir dengan duplikat untuk (company_id,org_path), memiliki kolom identitas eksplisit (semacam "pengungkap unik") akan membuatnya lebih mudah untuk menargetkan hanya satu di antaranya untuk dihapus atau diperbarui.

Martin Smith
sumber
12

Satu hal yang perlu dipertimbangkan adalah bahwa Kunci Utama dan Indeks Berkelompok bukan hal yang sama. Kunci Utama adalah kendala dan berkaitan dengan aturan yang digunakan data tersebut (yaitu integritas data); tidak ada hubungannya dengan efisiensi / kinerja. Kunci Utama mengharuskan kolom kunci unik (dalam kombinasi) dan BUKAN NULL (satu per satu). PK diberlakukan melalui Indeks Unik, meskipun dapat berupa Clustered atau Non-Clustered.

A Clustered Index adalah sarana untuk secara fisik (yaitu pada disk) memesan data dalam tabel dan berhubungan dengan kinerja; tidak ada hubungannya dengan integritas data. Indeks Clustered bisamengharuskan kolom kunci unik (dalam kombinasi), tetapi tidak perlu. Namun, karena Indeks Clustered adalah urutan fisik data, itu perlu mengidentifikasi setiap baris secara unik apa pun yang terjadi. Jadi, jika Anda tidak mengaturnya untuk membutuhkan keunikan, itu akan membuat keunikannya sendiri melalui kolom "uniquifier" 4 byte yang tersembunyi. Kolom itu selalu ada di Non-Unique Clustered Indexes, tetapi tidak memakan ruang apa pun ketika bidang kunci unik (dalam kombinasi). Untuk melihat secara langsung bagaimana kolom "uniquifier" ini bekerja (baik dalam Clustered Index dan pengaruhnya terhadap Non-Clustered Indexes), silakan periksa skrip pengujian yang saya posting di PasteBin: T-SQL script untuk menguji ukuran Uniquifier .

Oleh karena itu, pertanyaan utama:

apakah akan lebih efisien untuk menambahkan idbidang kenaikan-otomatis dan menggunakannya bersamaan dengan company_idsebagai kunci utama, atau apakah akan menambah overhead yang tidak perlu

adalah menggabungkan kedua konsep itu, sehingga mereka perlu ditangani secara terpisah, meskipun pasti ada beberapa tumpang tindih.

Haruskah IDENTITYkolom ditambahkan atau apakah itu overhead yang tidak perlu?

Jika Anda menambahkan INT IDENTITYkolom dan menggunakannya untuk membuat PK, dengan asumsi itu akan menjadi PK Clustered, yang menambahkan 4 byte ke setiap baris. Kolom ini terlihat dan dapat digunakan dalam kueri. Itu bisa ditambahkan ke tabel lain sebagai Kunci Asing, meskipun dalam kasus khusus ini tidak akan terjadi.

Jika Anda tidak menambahkan INT IDENTITYkolom, maka Anda tidak dapat membuat PK di tabel ini. Namun, Anda masih bisa membuat Indeks Berkelompok di atas meja selama Anda tidak menggunakan UNIQUEopsi. Dalam hal ini, SQL Server akan menambahkan kolom tersembunyi yang disebut "uniquifier" yang berperilaku seperti dijelaskan di atas. Karena kolom disembunyikan, itu tidak dapat digunakan dalam permintaan atau sebagai referensi untuk Kunci Asing.

Sejauh efisiensi berjalan, opsi-opsi ini kira-kira sama. Ya, akan ada sedikit lebih sedikit ruang yang diambil dengan memiliki Non-Unique Clustered Index karena beberapa baris (yang dengan nilai kunci unik awal) mengambil 0 byte sementara semua baris di IDENTITY/ PK akan mengambil 4 byte. Tetapi tidak akan ada cukup baris 0 byte (terutama dengan jumlah baris kecil yang diharapkan) untuk melihat perbedaan, apalagi menimbang kenyamanan untuk dapat menggunakan IDkolom dalam kueri.

INT IDENTITY Kolom atau Kolom Hash of org_pathPersistent Computed?

Mengingat bahwa Anda tidak akan mencari baris berdasarkan org_pathnilai, maka tidak masuk akal untuk menambahkan overhead Kolom yang Dikomputasi Persisten ditambah perlu menghitung hash dalam kueri untuk mencocokkan dengan Kolom yang Dihitung (ini adalah milik saya saran asli, tersedia dalam riwayat revisi di sini , yang didasarkan pada kata-kata awal / rincian Pertanyaan). Dalam kasus khusus ini, INT IDENTITYKolom "ID" mungkin yang terbaik.

Urutan Kolom Kunci

Mengingat bahwa IDKolom akan jarang, jika pernah, digunakan dalam permintaan, dan mengingat bahwa dua kasus penggunaan utama adalah untuk mendapatkan "semua baris" atau "semua baris untuk suatu pemberian company_id", saya akan membuat PK aktif company_id, id. Dan karena ini berarti bahwa baris tidak dimasukkan secara berurutan, saya akan menentukan nilai FILLFACTOR90. Anda juga perlu memastikan untuk melakukan pemeliharaan indeks secara teratur untuk mengurangi fragmentasi.

Pertanyaan kedua

apakah fakta bahwa company_id adalah kunci utama dalam tabel lain berpengaruh di sini

Tidak.

Pelatuk

Karena org_pathnilai-nilai dalam a company_idadalah unik, Anda masih harus membuat Trigger INSERT, UPDATEuntuk menegakkan ini. Di Trigger, lakukan IF EXISTSdengan kueri yang mungkin dilakukan a COUNT(*)dan GROUP BY company_id, org_path. Jika ada yang ditemukan, keluarkan a ROLLBACKuntuk membatalkan operasi DML dan RAISERRORpepatah yang mengatakan ada duplikat.

Pemeriksaan

Dalam jawaban awal saya (berdasarkan perincian kata-kata asli / jarang dari pertanyaan, dan tersedia dalam sejarah revisi di sini ), saya telah menyarankan kemungkinan menggunakan _BIN2Kolasi biner (yaitu ). Sekarang kita memiliki wawasan tentang apa sebenarnya org_path, saya tidak akan merekomendasikan menggunakan Kolasi biner. Karena akan ada tanda diakritik, Anda jangan ingin memanfaatkan ekuivalensi linguistik.

Solomon Rutzky
sumber
Mari kita lanjutkan diskusi ini dalam obrolan .
Solomon Rutzky
0

Mengapa Anda membutuhkan PK?

Mengapa tidak langsung menggunakan company_id sebagai indeks non-cluster?

Anda mengatakan bahwa yang paling dicari adalah pada semua entri atau oleh company_id
Jarang memperbarui
Jarang menghapus
org_path, ini adalah satu-satunya tabel di mana ada

Jawaban dari Martin Smith mungkin mendapatkan apa yang Anda butuhkan
Saya tidak akrab dengan secara otomatis menambahkan bilangan bulat 4 byte uniqueifier
Mungkin aku kehilangan sesuatu tapi jika Anda tidak memiliki kolom lain diindeks maka saya tidak melihat tujuan untuk itu dalam hal ini menggunakan

Jika Anda khawatir tentang DRI tabel harus menggunakan tabel Perusahaan sebagai FK untuk company_id

paparazzo
sumber
Hei. Mengenai " Mengapa tidak pergi dengan company_id sebagai indeks non-clustered? ": Karena itu akan memiliki 2 sisi-bawah: 1) itu akan menjadi 1 hal lagi mengambil ruang sedangkan Indeks Clustered adalah tabel sehingga tidak ada item tambahan, dan 2) masih akan membutuhkan pencarian RID untuk mendapatkan bidang NVARCHAR, kecuali itu INCLUDEkolom, tapi itu lebih buruk karena hanya menduplikasi tabel. Benar, PK tidak perlu; bagian penting adalah Indeks Clustered. Tapi begitu Anda memiliki IDENTITAS, mungkin juga pergi dengan PK. Dan tolong lihat tautan baru dalam jawaban saya untuk walk-through di Uniquifier 😃
Solomon Rutzky
@srutzky Tapi itu menghindari unikifier integer 4 byte jadi saya melihat itu sebagai cuci
paparazzo
Dengan kurang dari 10rb baris, itu tidak masalah; Anda mungkin perlu berada di jutaan baris sebelum Anda melihat efek hanya 4 byte. Jadi untuk kueri "dapatkan semua baris" sebenarnya tidak ada perbedaan dalam semua opsi ini. Tetapi untuk permintaan "get for company_id = @param", memiliki data yang dipesan secara fisik oleh company_id akan membantu, terutama ketika itu tidak perlu melakukan pencarian RID untuk setiap baris.
Solomon Rutzky
@srutzky Wash adalah cuci - 10K atau 1G. Itu hanya sesuatu yang perlu dipertimbangkan OP.
paparazzo