[Phần 1 | Phần 2 | Phần 3 | Phần 4]
Trong phần đầu tiên của loạt bài này, tôi đã trình bày điều gì sẽ xảy ra với một trang vật lý khi thay đổi cột IDENTITY từ int thành bigint. Để giữ cho mọi thứ đơn giản, tôi đã tạo một đống rất đơn giản không có chỉ mục hoặc ràng buộc. Thật không may, hầu hết chúng ta không có được sự sang trọng đó - một bảng quan trọng cần phải thay đổi nhưng không thể đơn giản được tạo lại từ đầu có thể có nhiều thuộc tính trực tiếp cản đường chúng ta. Trong bài đăng này, tôi muốn hiển thị những thứ phổ biến hơn mà không cần đi sâu vào những thứ kỳ lạ như In-Memory OLTP và Columnstore.
Khóa chính
Hy vọng rằng tất cả các bảng của bạn đều có khóa chính; tuy nhiên, nếu có liên quan đến cột IDENTITY, sẽ không dễ dàng như vậy để thay đổi kiểu dữ liệu cơ bản. Lấy các ví dụ đơn giản sau, cả khóa chính nhóm và khóa chính không gộp:
CREATE TABLE dbo.Test1 ( ID INT IDENTITY(1,1), CONSTRAINT PK_1 PRIMARY KEY NONCLUSTERED (ID) ); CREATE TABLE dbo.Test2 ( ID INT IDENTITY(1,1), CONSTRAINT PK_2 PRIMARY KEY CLUSTERED (ID) );
Nếu tôi cố gắng thay đổi cột:
ALTER TABLE dbo.Test1 ALTER COLUMN ID BIGINT; GO ALTER TABLE dbo.Test2 ALTER COLUMN ID BIGINT;
Tôi nhận được một cặp thông báo lỗi cho mỗi ALTER (chỉ hiển thị cặp đầu tiên):
Msg 5074, Level 16, State 1Đối tượng 'PK_1' phụ thuộc vào cột 'ID'.
Msg 4922, Level 16, State 9
ALTER TABLE ALTER COLUMN ID thất bại vì một hoặc nhiều đối tượng hơn truy cập vào cột này.
Tóm tắt:Chúng tôi sẽ cần bỏ khóa chính , có được phân cụm hay không.
Chỉ mục
Đầu tiên, hãy lấy một vài bảng như trên và sử dụng một chỉ mục duy nhất thay vì khóa chính:
CREATE TABLE dbo.Test3 ( ID INT IDENTITY(1,1), INDEX IX_3 UNIQUE NONCLUSTERED (ID) ); CREATE TABLE dbo.Test4 ( ID INT IDENTITY(1,1), INDEX IX_4 UNIQUE CLUSTERED (ID) );
Chạy các lệnh ALTER tương tự ở trên, dẫn đến các thông báo lỗi giống nhau. Điều này vẫn đúng ngay cả khi tôi tắt các chỉ mục:
ALTER INDEX IX_3 ON dbo.Test3 DISABLE; GO ALTER INDEX IX_4 ON dbo.Test4 DISABLE;
Các kết quả tương tự cho nhiều loại kết hợp chỉ mục khác, chẳng hạn như cột được bao gồm hoặc bộ lọc:
CREATE TABLE dbo.Test5 ( ID INT IDENTITY(1,1), x CHAR(1) ); CREATE INDEX IX_5 ON dbo.Test5(x) INCLUDE(ID); CREATE TABLE dbo.Test6 ( ID INT IDENTITY(1,1), x CHAR(1) ); CREATE INDEX IX_6 ON dbo.Test6(x) WHERE ID > 0;
Tóm tắt:Chúng tôi sẽ cần loại bỏ và tạo lại bất kỳ chỉ mục nào , được nhóm hoặc không, tham chiếu đến cột IDENTITY - trong khóa hoặc INCLUDE. Nếu cột IDENTITY là một phần của chỉ mục được nhóm lại, điều này có nghĩa là tất cả các chỉ mục , vì tất cả chúng sẽ tham chiếu đến khóa phân cụm theo định nghĩa. Và vô hiệu hóa chúng là không đủ.
Cột được Tính
Mặc dù điều này tương đối hiếm, nhưng tôi đã thấy các cột được tính toán dựa trên cột IDENTITY. Ví dụ:
CREATE TABLE dbo.Test7 ( ID INT IDENTITY(1,1), NextID AS (ID + 1) );
Lần này, khi chúng tôi cố gắng thay đổi, chúng tôi nhận được cùng một cặp lỗi, nhưng với văn bản hơi khác:
Msg 5074, Level 16, State 1Cột 'NextID' phụ thuộc vào cột 'ID'.
Msg 4922, Level 16, State 9
ALTER TABLE ALTER COLUMN ID thất bại vì một hoặc nhiều đối tượng hơn truy cập vào cột này.
Điều này thậm chí đúng nếu chúng tôi thay đổi định nghĩa cột được tính toán để phù hợp với kiểu dữ liệu đích:
CREATE TABLE dbo.Test8 ( ID INT IDENTITY(1,1), NextID AS (CONVERT(BIGINT, ID) + 1) );
Tóm tắt:Chúng tôi sẽ cần thay đổi định nghĩa của các cột được tính toán hoặc loại bỏ chúng hoàn toàn.
Lượt xem được lập chỉ mục
Chế độ xem được lập chỉ mục cũng cho thấy tỷ lệ sử dụng hợp lý của họ. Hãy tạo một dạng xem được lập chỉ mục thậm chí không tham chiếu đến cột IDENTITY (lưu ý không có chỉ mục hoặc ràng buộc nào khác trên bảng cơ sở):
CREATE TABLE dbo.Test9 ( ID INT IDENTITY(1,1), x CHAR(1) ); GO CREATE VIEW dbo.vTest9A WITH SCHEMABINDING AS SELECT x, c = COUNT_BIG(*) FROM dbo.Test9 GROUP BY x; GO CREATE UNIQUE CLUSTERED INDEX IX_9A ON dbo.vTest9A(x);
Một lần nữa, chúng tôi sẽ thử ALTER và lần này nó thành công . Thú thực là tôi đã rất ngạc nhiên vì điều này, vì SCHEMABINDING được cho là ngăn chặn bất kỳ thay đổi nào đối với bảng bên dưới, nhưng trong trường hợp này, nó chỉ áp dụng cho các cột được tham chiếu rõ ràng trong chế độ xem. Nếu chúng ta tạo một chế độ xem hơi khác:
CREATE VIEW dbo.vTest9B WITH SCHEMABINDING AS SELECT ID, c = COUNT_BIG(*) FROM dbo.Test9 GROUP BY ID; GO CREATE UNIQUE CLUSTERED INDEX IX_9B ON dbo.vTest9B(ID);
Bây giờ chúng ta sẽ thất bại do sự phụ thuộc của cột:
Msg 5074, Level 16, State 1Đối tượng 'vTest9B' phụ thuộc vào cột 'ID'.
Msg 4922, Level 16, State 9
ALTER TABLE ALTER COLUMN ID thất bại vì một hoặc nhiều đối tượng hơn truy cập vào cột này.
Tóm tắt:Chúng tôi sẽ cần loại bỏ tất cả các chỉ mục trên bất kỳ chế độ xem nào tham chiếu rõ ràng đến cột IDENTITY , cũng như tất cả các chỉ mục trên bất kỳ chế độ xem nào tham chiếu đến cột IDENTITY trong chỉ mục được nhóm của nó.
Khóa nước ngoài vào
Có lẽ khía cạnh vấn đề nhất của khóa chính IDENTITY là về bản chất của các khóa thay thế, toàn bộ điểm thường là sử dụng khóa thay thế này trong nhiều bảng có liên quan. Bây giờ, tôi không định ủng hộ việc tránh tính toàn vẹn tham chiếu, nhưng nó cũng có khả năng cản trở chúng ta một chút ở đây. Ở trên, chúng ta biết rằng chúng ta không thể thay đổi cột là một phần của khóa chính hoặc ràng buộc duy nhất, và để một bảng khác trỏ đến đây với ràng buộc khóa ngoại, một trong hai thứ đó phải tồn tại. Vì vậy, giả sử chúng ta có hai bảng sau:
CREATE TABLE dbo.TestParent ( ID INT IDENTITY(1,1), CONSTRAINT PK_Parent PRIMARY KEY CLUSTERED(ID) ); GO CREATE TABLE dbo.TestChild ( ParentID INT NOT NULL, CONSTRAINT FK_Parent FOREIGN KEY(ParentID) REFERENCES dbo.TestParent(ID) );
Trước khi có thể xem xét việc thay đổi kiểu dữ liệu của cột, chúng ta cần loại bỏ ràng buộc:
ALTER TABLE dbo.TestParent DROP CONSTRAINT PK_Parent;
Và tất nhiên, chúng tôi không thể, mà không bỏ ràng buộc khóa ngoại, vì điều này dẫn đến thông báo lỗi sau:
Msg 3725, Level 16, State 0Ràng buộc 'PK_Parent' đang được tham chiếu bởi bảng 'TestChild', ràng buộc khóa ngoại 'FK_Parent'.
Msg 3727, Level 16, State 0
Could không giảm ràng buộc. Xem các lỗi trước đó.
Lỗi này vẫn xảy ra ngay cả khi lần đầu tiên chúng tôi vô hiệu hóa ràng buộc khóa ngoại:
ALTER TABLE dbo.TestChild NOCHECK CONSTRAINT FK_Parent;
Trên hết, hãy cân nhắc rằng bạn cũng sẽ cần các cột tham chiếu để thay đổi kiểu dữ liệu của chúng. Và xa hơn nữa, những cột đó có thể tham gia vào một số phần tử trên có thể ngăn cản sự thay đổi trên các bảng con. Để mọi thứ hoàn toàn đồng bộ và đồng bộ, chúng ta sẽ phải:
- bỏ các ràng buộc và chỉ mục có liên quan trên bảng mẹ
- bỏ các ràng buộc khóa ngoại có liên quan trên các bảng con
- bỏ bất kỳ chỉ mục nào trên các bảng con tham chiếu đến cột FK (và xử lý mọi cột được tính toán có liên quan / chế độ xem được lập chỉ mục)
- thay đổi kiểu dữ liệu trên bảng mẹ và tất cả các bảng con
- tạo lại mọi thứ
Tóm tắt:Chúng tôi sẽ cần loại bỏ các khóa ngoại đến và, có khả năng, điều này sẽ có một loạt các hiệu ứng xếp tầng. Chỉ vô hiệu hóa các khóa ngoại là không đủ và dù sao cũng sẽ không phải là giải pháp lâu dài, vì kiểu dữ liệu cuối cùng cũng sẽ phải thay đổi trong các bảng con.
Kết luận
Tôi biết có vẻ như chúng ta đang di chuyển chậm và tôi thừa nhận rằng trong bài đăng này, tôi dường như đang rút ra khỏi một giải pháp hơn là hướng tới một giải pháp. Tôi sẽ đến đó, chỉ có rất nhiều thông tin cần trình bày trước, bao gồm cả những thứ khiến loại hình thay đổi này trở nên khó khăn. Có được từ các tóm tắt ở trên, chúng tôi sẽ cần:
- thả và tạo lại các chỉ mục có liên quan trên bảng chính
- thay đổi hoặc bỏ các cột được tính liên quan đến cột IDENTITY
- giảm chỉ mục trên các chế độ xem được lập chỉ mục tham chiếu đến cột IDENTITY
- xử lý các khóa ngoại gửi đến trỏ đến cột IDENTITY
Thật không may, rất nhiều thứ trong số này là bắt-22. Bạn không thể thay đổi một cột vì một chỉ mục dựa vào nó và bạn không thể thay đổi chỉ mục cho đến khi cột đó đã thay đổi. Thật tuyệt nếu ALTER INDEX hỗ trợ REBUILD WITH (ONLINE = ON, CHANGE_COLUMN (COLUMN = ID, NEW_TYPE = BIGINT))
? Và CASCADE_CHANGE_TO_REFERENCING_KEYS,COLUMNS,INDEXES,VIEWS,ETC
? Chà, nó không (tôi đã kiểm tra). Vì vậy, chúng ta cần tìm cách biến những việc này trở nên dễ dàng hơn. Hãy theo dõi Phần 3.
-
[Phần 1 | Phần 2 | Phần 3 | Phần 4]