Mengapa IDENTITY_INSERT ON hanya diperbolehkan di satu meja pada satu waktu?


20

Ini adalah kasus yang IDENTITY_INSERT hanya dapat diatur untuk ON di satu tabel database pada suatu waktu, tapi mengapa? Karena IDENTITYkolom tidak unik secara global, saya tidak dapat memikirkan situasi berbahaya apa pun yang dapat disebabkan oleh memasukkan identitas ke lebih dari satu tabel pada saat yang sama (setidaknya tidak lebih berbahaya daripada umumnya memperdaya dengan IDENTITY INSERT).

INSENTITAS IDENTITAS harus jarang digunakan tetapi apa alasan untuk batas yang sulit?


1
Jera mungkin, jadi jarang digunakan?
Remus Rusanu

@RemusRusanu semacam itulah yang saya pikirkan, baik itu atau untuk memastikan Anda tidak sengaja meninggalkan II ON untuk beberapa tabel.
Ben Brocka

@ Lalu mengapa meninggalkannya secara tidak sengaja untuk beberapa tabel lebih buruk daripada secara tidak sengaja membiarkannya secara tidak sengaja untuk satu meja? Keduanya dapat menyebabkan masalah yang sama. Saya benar-benar ingin tahu tentang pertanyaan Anda, dan saya tidak berpikir jera adalah jawabannya, atau kita akan memiliki lebih banyak pembatasan di mesin. Tetapi saya setuju bahwa jika Anda merasa perlu sering melakukan ini, mungkin ada sesuatu yang mencurigakan.
Aaron Bertrand

@ AaronBertrand bukan, seperti yang saya tersirat di Q. Tidak yakin tentang jera juga, karena SQL Server memungkinkan banyak praktik buruk lainnya seperti penamaan kolom Anda dengan kata kunci yang dipesan (kadang-kadang bahkan jika Anda tidak menggunakan []!)
Ben Brocka

@Ben benar itu tidak harus untuk Anda tetapi untuk setiap pembaca yang menemukan pertanyaan.
Aaron Bertrand

Jawaban:


12

Saya pikir itu untuk membuatnya sulit. Jika Anda bisa membiarkannya sepanjang waktu, mengapa harus memiliki bidang identitas?

Namun sebenarnya ada beberapa batasan:

  • Itu hanya ada pada koneksi itu
  • Ini hanya dapat diatur pada satu meja per koneksi

Berdasarkan batasan yang berhubungan dengan koneksi, saya pikir itu terutama sehingga tidak pernah sengaja dinyalakan.

Bayangkan jika seseorang menyalakan ID sisipan di salah satu tabel Anda, maka Anda tidak menyadari dan dilakukan penyisipan yang tidak valid yang merusak integritas bidang ID Anda?

Ingatlah, bidang ID dapat memiliki nilai duplikat jika tidak ada kendala atau indeks unik di tempat ...


1
+1 Saya pikir poin terakhir Anda tentang duplikat banyak dilewatkan. Orang-orang berpikir jika mereka mengaturnya IDENTITYjuga menjadi kendala yang unik. Sangat mudah dibantah, tentu saja, jika mereka mau mencobanya.
Aaron Bertrand

@ AaronBertrand Tetapi sekali lagi, risiko duplikat ID persis sama pada setiap tabel dengan IDENTITY INSERT pada, mengapa batas kerasnya? Saya pikir fakta bahwa itu hanya bertahan untuk koneksi lebih masuk akal sebagai tindakan pencegahan.
Ben Brocka

Saya tidak menyarankan masalah duplikat ID adalah alasan untuk batas yang sulit.
Aaron Bertrand

6

Tebakan saya adalah pembatasan karena implementasi. Mengizinkan pengaturan ini pada beberapa tabel adalah performa yang potensial:

Karena ini adalah parameter sesi, memungkinkan pengaturan untuk diaktifkan pada tabel tunggal berarti bahwa itu adalah flag sederhana dan id objek tabel untuk disimpan pada sesi, sisi server. Mungkin ini hanya satu bilangan bulat: 0 jika tidak ada IDENTITY_INSERT aktif, dan beberapa pengkodean databaseid + objectid untuk tabel.

Mengizinkan parameter ditetapkan pada beberapa tabel dalam satu sesi akan berarti bahwa server akan menyimpan daftar objek yang dinamis dan memeriksanya untuk setiap pernyataan penyisipan. Bayangkan sebuah sesi mengaktifkan parameter untuk seribu tabel:

  1. Ini berarti server telah mengalokasikan 1000 item dalam variabel sesi
  2. Ini juga berarti bahwa server harus memeriksa daftar 1000 item untuk setiap pernyataan penyisipan dalam sesi ini.

Saya juga curiga bahwa set identity_insert on memiliki kinerja yang sangat baik di server. Dalam sybase ada " faktor pembakaran identitas ", yang memungkinkan untuk menyimpan nilai penghitung identitas suatu tabel untuk disimpan hanya sesekali (nilai disimpan dalam memori dan ditulis ke disk sesekali dan di server matikan ). SQL Server didasarkan pada kode yang sama sehingga mungkin memiliki beberapa optimasi yang sebanding, tetapi mengaktifkan identity_insert di atas meja mungkin membatasi server untuk menyimpan nilai identitas untuk setiap sisipan, karena selain itu tidak dapat menjamin ukuran celah maksimum. Jadi, jika satu sesi membuat hit kinerja pada sisipan dalam satu tabel ini mungkin dapat diterima, tetapi tidak jika itu dapat membuat perf hit pada semua tabel auto_increment di server ..


+1 Mungkin ada kebenaran di sini. Saya tidak membeli argumen ukuran kesenjangan, karena hanya satu yang INSERTdapat dilakukan pada satu waktu untuk satu sesi, dan saya dapat dengan mudah memasukkan 10 juta nilai hard-coded IDENTITY.
Aaron Bertrand

Ukuran celah terkait dengan apa yang terjadi dalam kasus kerusakan: pada sybase, jika server mogok identitas terakhir hilang (dalam memori), sehingga memulai kembali dengan meninggalkan celah (lihat set factor pembakaran identitas)
Olivier S

Jadi dalam SQL Server apakah Anda menyarankan sesuatu yang berbeda terjadi jika mesin crash saat memasukkan 1.000.000 baris dengan kolom identitas, atau mengesampingkan kolom identitas dengan 1.000.000 nilai hard-kode saat SET IDENTITY_INSERTdiaktifkan? Saya hanya menyarankan bahwa ukuran celah tidak mempengaruhi beberapa tabel berbeda dari itu mempengaruhi satu tabel.
Aaron Bertrand

Dugaan saya - saya sama sekali tidak punya bukti tentang ini - adalah bahwa SET IDENTITY_INSERT pada sebuah tabel memaksa write-to-disk dari autoincrement pada setiap insert. Alasannya adalah karena nilai yang Anda masukkan bisa apa saja, server tidak dapat mempertimbangkan "ok, jika saya menulis ke disk hanya setiap 1000 baris, jika terjadi kerusakan saya dapat menambahkan 1000 dengan aman ke nilai terakhir yang saya simpan"
Olivier S
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.