Mengapa menghapus properti Identity pada kolom tidak didukung

11

Saya telah membaca bahwa setelah SQL Server 2000, kemampuan untuk "menghapus identitas" kolom identitas dihapus. Dan ini adalah "By Design" (bukan hanya fitur yang hilang).

Ini adalah contoh yang saya temukan di sebuah blog . Ini melibatkan memperbarui tabel sistem. (Dan kemampuan itu dihapus setelah SQL Server 2000.) Saya mendapatkan bahwa melakukan ini melalui tabel sistem bukanlah ide yang baik. Saya hanya ingin tahu mengapa fitur untuk melakukan ini dengan cara lain tidak ada.

Mengatasi hal ini akan menyebabkan saya banyak bekerja. (Menyalin ratusan juta baris ke tabel baru di lingkungan yang tidak toleran dengan waktu henti.)

Jadi saya pikir saya akan bertanya "Kenapa".

Apa yang berubah di Sql Server 2005 dan versi yang lebih baru yang menjadikan ini hal yang buruk? Atau apakah itu selalu buruk, dan tidak dikunci?

Apa "Praktik Terbaik" (atau prinsip serupa) apa yang akan dilanggar dengan menjadikan kolom identitas sebagai kolom normal lagi?

-

Perbarui untuk menjawab permintaan "mengapa saya melakukan ini":
Ini adalah ringkasan tingkat yang sangat tinggi: Saya akan mulai menambahkan partisi ke tabel saya. (Sehingga saya dapat mengarsipkan / membersihkan data lama.) Itu semua mudah. Tapi kadang-kadang saya perlu memindahkan catatan ke partisi yang berbeda agar tidak dihapus (ketika sebuah partisi muncul untuk arsip / penghapusan). (Saya meminta kolom partisi saya bertambah 2 sehingga selalu ada ruang untuk memindahkan baris ke partisi lain.)

Tetapi jika kolom partisi adalah kolom identitas, maka saya harus menghapus dan memasukkan kembali nilainya (tidak ada cara untuk memperbarui nilai kolom identitas). Yang menyebabkan masalah dengan replikasi.

Jadi saya ingin menggunakan urutan alih-alih kolom identitas. Tetapi peralihan itu sangat sulit pada basis data besar.

Gunung berapi
sumber

Jawaban:

22

Pertanyaan Anda pada dasarnya adalah:

Mengapa saya tidak bisa lagi melakukan hal berisiko ini yang semestinya tidak pernah saya boleh lakukan?

Jawaban atas pertanyaan itu sebagian besar tidak relevan (meskipun Anda dapat melihat beberapa komentar Microsoft di item Connect ini yang menanyakan fungsi ini: # 294193 dan # 252226). Untuk kelengkapan, sinopsis saya adalah: Kemampuan untuk menghapus properti identitas adalah efek samping yang tidak diinginkan karena memiliki kemampuan untuk mengacaukan tabel sistem di tempat pertama. Ini tidak dimaksudkan untuk digunakan dalam banyak hal, seringkali dengan konsekuensi yang sangat buruk, dan karenanya dihilangkan. Itu adalah hack tabel sistem tidak berdokumen, tidak didukung. Kemampuan untuk mengubah data dalam tabel sistem tidak dihapus karena Microsoft tidak lagi ingin Anda meretas jalan Anda keluar dari kolom menjadi kolom identitas, itu dihapus karena mucking dengan tabel sistem sangat berisiko. Menghapus properti IDENTITY itu sendiri bukanlah penghapusan fitur yang ditargetkan secara spesifik, dan saya tidak akan pernah sepenuhnya mempercayai pendekatan ini bahkan di masa lalu ketika hal itu memungkinkan.

Yang mengatakan, bagaimana kalau kita menjawab pertanyaan ini?

Bagaimana cara menghapus properti IDENTITY kolom dengan downtime minimal atau tidak ada?

Ini dapat Anda lakukan dengan mudah, menggunakan ALTER TABLE ... SWITCH, teknik yang saya yakin pertama kali saya pelajari dari Paul White kami sendiri dalam penyelesaian untuk Connect # 252226 . Contoh cepat, diberikan tabel sederhana ini:

CREATE TABLE dbo.Original
(
  ID INT IDENTITY(1,1) PRIMARY KEY,
  name SYSNAME
);
GO

INSERT dbo.Original(name) VALUES(N'foo'),(N'bar');
GO

SELECT * FROM dbo.Original;
GO

Hasil:

ID  name
--  ----
1   foo
2   bar

Sekarang, mari kita buat tabel bayangan, dan beralih ke sana, lalu jatuhkan tabel lama, ganti nama yang baru, dan kemudian lanjutkan aktivitas normal:

CREATE TABLE dbo.New
(
  ID INT PRIMARY KEY,
  name SYSNAME
);
GO

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
  ALTER TABLE dbo.Original SWITCH TO dbo.New;
  DROP TABLE dbo.Original;
  EXEC sys.sp_rename N'dbo.New', N'Original', 'OBJECT';
COMMIT TRANSACTION;
GO

INSERT dbo.Original(ID,name) VALUES(3,N'splunge');
UPDATE dbo.Original SET ID = 6 WHERE ID = 1;
GO

SELECT * FROM dbo.Original;
GO

Hasil:

ID  name
--  -------
2   bar
3   splunge
6   foo

Sekarang bersihkan:

DROP TABLE dbo.Original;

Ini hanya operasi metadata, tanpa pergerakan data, dan hanya akan memblokir pengguna lain saat metadata sedang diperbarui. Tapi, harus diakui, ini adalah contoh yang sangat sederhana. Jika Anda memiliki kunci asing atau menggunakan fitur lain seperti replikasi, Ubah Pengambilan Data, Ubah Pelacakan, dll. Anda mungkin perlu menonaktifkan atau menghapus beberapa di antaranya sebelum membuat perubahan ini (Saya belum menguji semua kombinasi). Khusus untuk kunci asing, lihat tip ini yang menunjukkan cara membuat skrip untuk menghapus dan membuat kembali semua (atau memilih) batasan kunci asing.

Selain itu, Anda perlu memperbarui kode aplikasi Anda untuk tidak mengharapkan SQL Server mengisi kolom ini, dan memeriksa setiap penyisipan atau pilih pernyataan yang mungkin tergantung pada urutan kolom atau kolom yang mereka perlu tentukan. Secara umum, saya akan grep seluruh basis kode Anda untuk menyebutkan tabel ini.

Juga lihat skrip ini dari Itzik Ben-Gan (sumber: artikel kuno ini ) untuk cara lain untuk menangani ini, tetapi ada pergerakan data yang terlibat di sini, sehingga tidak memenuhi persyaratan "tidak ada atau minimal waktu henti".

Aaron Bertrand
sumber
3
Saya ingin mendorong siapa pun yang datang untuk mengunggah kedua item terhubung. Seberapa sulit untuk mengimplementasikan fitur ALTER COLUMN yang menghidupkan atau mematikan identitas boolean ?! Susah bekerja di sekitar.
usr
Saya harus mengakui, untuk beberapa alasan saya pikir itu ..SWITCH..hanya bekerja untuk tabel yang memiliki setidaknya satu partisi yang ditentukan.
RBarryYoung
Hanya ingin menambahkan yang SWITCHtidak memerlukan Edisi Perusahaan, meskipun partisi tabel tidak.
Dan Guzman