"Cegah perubahan simpanan yang mengharuskan tabel dibuat ulang" efek negatifnya

255

Pembukaan

Saya memodifikasi kolom di SQL Server 2008 hari ini, mengubah tipe data dari sesuatu seperti mata uang (18,0) menjadi (19,2).

Saya mendapat kesalahan "Perubahan yang Anda buat membutuhkan tabel berikut untuk dihapus dan dibuat ulang" dari SQL Server.

Sebelum Anda mencoba menjawab, harap baca yang berikut:

Saya sudah tahu ada opsi di Alat ► Opsi ► Desainer ► Desainer Tabel dan Database ► Hapus centang pada kotak "Cegah perubahan simpanan yang memerlukan pembuatan ulang tabel." Cegah perubahan simpanan yang membutuhkan pembuatan ulang tabel dalam lima klik ... jadi jangan jawab dengan itu!

Pertanyaan aktual

Pertanyaan saya yang sebenarnya adalah untuk hal lain, sebagai berikut:

Apakah ada efek negatif / kemungkinan kelemahan melakukan ini?

Apakah tabel benar-benar jatuh dan diciptakan kembali secara otomatis ketika kotak ini tidak dicentang?

Jika demikian, apakah tabel menyalin replika persis 100% dari tabel sumber?

CF_HoneyBadger
sumber
65
Alat> Opsi> Desainer ... itulah yang saya cari! Terima kasih!
nrod
2
Dan jika Anda menggunakan MS SQL Server 2014 -> Ekstra> Opsi> Desainer Dari menu atas.
Vityata

Jawaban:

89

Tabel hanya dijatuhkan dan dibuat kembali dalam kasus di mana itulah satu-satunya cara Studio Manajemen SQL Server telah diprogram untuk mengetahui bagaimana melakukannya.

Tentu saja ada kasus di mana ia akan melakukan itu ketika tidak perlu, tetapi juga akan ada kasus di mana Anda mengedit di Studio Manajemen tidak akan jatuh dan dibuat kembali karena tidak harus.

Masalahnya adalah bahwa menghitung semua kasus dan menentukan di sisi mana mereka jatuh akan sangat membosankan.

Inilah sebabnya mengapa saya suka menggunakan ALTER TABLEdi jendela permintaan, daripada desainer visual yang menyembunyikan apa yang mereka lakukan (dan terus terang memiliki bug) - Saya tahu persis apa yang akan terjadi, dan saya dapat mempersiapkan kasus-kasus di mana satu-satunya kemungkinan adalah menjatuhkan dan membuat ulang tabel (yang jumlahnya kurang dari seberapa sering SSMS akan melakukannya untuk Anda).

Aaron Bertrand
sumber
5
Meskipun jawaban yang sangat bagus, saya merasa itu tidak memberikan jawaban untuk semua pertanyaan yang diajukan oleh OP, dan pertanyaan-pertanyaan itu adalah yang saya tertarik, sebenarnya. Secara khusus Apakah ada efek negatif / kemungkinan kelemahan melakukan ini? dan Jika demikian, apakah tabel menyalin replika persis 100% dari tabel sumber? . Apakah Anda memiliki informasi mengenai pertanyaan-pertanyaan itu?
tfrascaroli
252

Alat -> Opsi -> simpul Desainer -> Hapus centang " Cegah perubahan simpanan yang memerlukan rekreasi tabel ".

Antoine Meltzheim
sumber
12

Referensi - Menonaktifkan opsi ini dapat membantu Anda menghindari membuat kembali tabel, ini juga dapat menyebabkan perubahan hilang. Misalnya, anggap Anda mengaktifkan fitur Ubah Pelacakan di SQL Server 2008 untuk melacak perubahan pada tabel. Saat Anda melakukan operasi yang menyebabkan tabel dibuat kembali, Anda menerima pesan galat yang disebutkan di bagian "Gejala". Namun, jika Anda mematikan opsi ini, informasi pelacakan perubahan yang ada dihapus ketika tabel dibuat kembali. Oleh karena itu, Microsoft menganjurkan agar Anda tidak mengatasi masalah ini dengan mematikan opsi.


sumber
11

SQL Server menjatuhkan dan membuat ulang tabel hanya jika Anda:

  • Tambahkan kolom baru
  • Ubah pengaturan Allow Nulls untuk kolom
  • Ubah urutan kolom dalam tabel
  • Ubah tipe data kolom

Menggunakan ALTER lebih aman, karena jika metadata hilang saat Anda membuat kembali tabel, data Anda akan hilang.

Carol Baker Barat
sumber
8
Daftar Anda tidak lengkap. Tambahkan / hapus IDENTITYproperti pada kolom, misalnya.
Aaron Bertrand
2
Menambahkan kolom baru ke ujung bidang yang NULLABLE tidak memerlukan tabel yang dibangun kembali.
PseudoToad
2

Ya, ada efek negatif dari ini:

Jika Anda membuat skrip perubahan yang diblokir oleh bendera ini, Anda akan mendapatkan skrip di bawah ini (semua saya mengubah kolom ID dalam Kontak menjadi kolom IDENTITAS bilangan otomatis, tetapi tabel memiliki dependensi). Catat potensi kesalahan yang dapat terjadi saat berikut ini berjalan:

  1. Bahkan microsoft memperingatkan bahwa ini dapat menyebabkan kehilangan data (komentar itu dihasilkan secara otomatis)!
  2. untuk jangka waktu tertentu, kunci asing tidak diberlakukan.
  3. jika Anda menjalankan ini secara manual dalam ssms dan 'EXEC (' INSERT INTO 'gagal, dan Anda membiarkan pernyataan berikut berjalan (yang dilakukan secara default, karena dibagi dengan' go ') maka Anda akan memasukkan 0 baris, lalu turun meja lama.
  4. jika ini adalah tabel besar, runtime dari insert bisa besar, dan transaksi tersebut menahan kunci modifikasi skema, jadi memblokir banyak hal.

-

/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/

BEGIN TRANSACTION
GO
ALTER TABLE raw.Contact
    DROP CONSTRAINT fk_Contact_AddressType
GO
ALTER TABLE ref.ContactpointType SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE raw.Contact
    DROP CONSTRAINT fk_contact_profile
GO
ALTER TABLE raw.Profile SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE raw.Tmp_Contact
    (
    ContactID int NOT NULL IDENTITY (1, 1),
    ProfileID int NOT NULL,
    AddressType char(2) NOT NULL,
    ContactText varchar(250) NULL
    )  ON [PRIMARY]
GO
ALTER TABLE raw.Tmp_Contact SET (LOCK_ESCALATION = TABLE)
GO
SET IDENTITY_INSERT raw.Tmp_Contact ON
GO
IF EXISTS(SELECT * FROM raw.Contact)
     EXEC('INSERT INTO raw.Tmp_Contact (ContactID, ProfileID, AddressType, ContactText)
        SELECT ContactID, ProfileID, AddressType, ContactText FROM raw.Contact WITH (HOLDLOCK TABLOCKX)')
GO
SET IDENTITY_INSERT raw.Tmp_Contact OFF
GO
ALTER TABLE raw.PostalAddress
    DROP CONSTRAINT fk_AddressProfile
GO
ALTER TABLE raw.MarketingFlag
    DROP CONSTRAINT fk_marketingflag_contact
GO
ALTER TABLE raw.Phones
    DROP CONSTRAINT fk_phones_contact
GO
DROP TABLE raw.Contact
GO
EXECUTE sp_rename N'raw.Tmp_Contact', N'Contact', 'OBJECT' 
GO
ALTER TABLE raw.Contact ADD CONSTRAINT
    Idx_Contact_1 PRIMARY KEY CLUSTERED 
    (
    ProfileID,
    ContactID
    ) 

GO
ALTER TABLE raw.Contact ADD CONSTRAINT
    Idx_Contact UNIQUE NONCLUSTERED 
    (
    ProfileID,
    ContactID
    ) 

GO
CREATE NONCLUSTERED INDEX idx_Contact_0 ON raw.Contact
    (
    AddressType
    ) 
GO
ALTER TABLE raw.Contact ADD CONSTRAINT
    fk_contact_profile FOREIGN KEY
    (
    ProfileID
    ) REFERENCES raw.Profile
    (
    ProfileID
    ) ON UPDATE  NO ACTION 
     ON DELETE  NO ACTION 

GO
ALTER TABLE raw.Contact ADD CONSTRAINT
    fk_Contact_AddressType FOREIGN KEY
    (
    AddressType
    ) REFERENCES ref.ContactpointType
    (
    ContactPointTypeCode
    ) ON UPDATE  NO ACTION 
     ON DELETE  NO ACTION 

GO
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE raw.Phones ADD CONSTRAINT
    fk_phones_contact FOREIGN KEY
    (
    ProfileID,
    PhoneID
    ) REFERENCES raw.Contact
    (
    ProfileID,
    ContactID
    ) ON UPDATE  NO ACTION 
     ON DELETE  NO ACTION 

GO
ALTER TABLE raw.Phones SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE raw.MarketingFlag ADD CONSTRAINT
    fk_marketingflag_contact FOREIGN KEY
    (
    ProfileID,
    ContactID
    ) REFERENCES raw.Contact
    (
    ProfileID,
    ContactID
    ) ON UPDATE  NO ACTION 
     ON DELETE  NO ACTION 

GO
ALTER TABLE raw.MarketingFlag SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE raw.PostalAddress ADD CONSTRAINT
    fk_AddressProfile FOREIGN KEY
    (
    ProfileID,
    AddressID
    ) REFERENCES raw.Contact
    (
    ProfileID,
    ContactID
    ) ON UPDATE  NO ACTION 
     ON DELETE  NO ACTION 

GO
ALTER TABLE raw.PostalAddress SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
Andrew Hill
sumber