“Prevent saving changes that require the table to be re-created” negative effects

前端 未结 5 858
抹茶落季
抹茶落季 2020-12-04 06:00

Preamble

I was modifying a column in SQL Server 2008 today, changing the datatype from something like currency(18,0) to (19,2).

I got the

5条回答
  •  庸人自扰
    2020-12-04 06:51

    Yes, there are negative effects from this:

    If you script out a change blocked by this flag you get something like the script below (all i am turning the ID column in Contact into an autonumbered IDENTITY column, but the table has dependencies). Note potential errors that can occur while the following is running:

    1. Even microsoft warns that this may cause data loss (that comment is auto-generated)!
    2. for a period of time, foreign keys are not enforced.
    3. if you manually run this in ssms and the ' EXEC('INSERT INTO ' fails, and you let the following statements run (which they do by default, as they are split by 'go') then you will insert 0 rows, then drop the old table.
    4. if this is a big table, the runtime of the insert can be large, and the transaction is holding a schema modification lock, so blocks many things.

    --

    /* 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
    

提交回复
热议问题