SQL Server: Thay đổi đối chiếu trên cơ sở dữ liệu hiện có an toàn không?


7

Tôi mới sử dụng SQL Server và không biết khả năng T-SQL có thể không phân biệt chữ hoa chữ thường.

Tôi đã bình thường hóa các thực thể bằng cách tách các bảng và các ràng buộc. Tôi sợ rằng nếu tôi thay đổi đối chiếu ngay bây giờ, thì một số ràng buộc đó có thể không hợp lệ nếu, ví dụ, giá trị khóa ngoài 'không phân biệt chữ hoa' chỉ ra giá trị PK với trường hợp khác.

Nếu tôi chạy truy vấn này trên DB (được thử nghiệm trên cơ sở dữ liệu cơ bản):

ALTER DATABASE <db_name>
COLLATE SQL_Latin1_General_Cp1_CS_AS ;
GO

Điều gì sẽ xảy ra nếu một số ràng buộc bị vi phạm?

Có bất kỳ lý do nào khác mà tôi nên cẩn thận thực hiện thay đổi trên toàn cơ sở dữ liệu như thay đổi đối chiếu không?

Câu trả lời:


6

Thay đổi Collation của cơ sở dữ liệu không ảnh hưởng đến các cột hiện có. Nó ảnh hưởng đến các cột chuỗi không phải XML mới được tạo mà không chỉ định COLLATEmệnh đề (bao gồm các biến bảng), chuỗi ký tự và giá trị biến (không phải là độ phân giải tên biến, được xác định bởi Đối chiếu mức Instance). Có nghĩa, một cái gì đó như sau sẽ bị ảnh hưởng:

IF (@Variable = 'string')
BEGIN
    ...
END;

Thay đổi này cũng sẽ ảnh hưởng đến dữ liệu meta cấp cơ sở dữ liệu, chẳng hạn như tên của lược đồ, đối tượng, cột, chỉ mục, v.v. Ý nghĩa, hai kịch bản sau đây sẽ bị ảnh hưởng:

SELECT ...
FROM   sys.indexes si
WHERE  si.[name] = N'somename'; -- real name = SomeName

và:

SELECT ...
FROM   dbo.sometable st -- real name = SomeTable

Trong cả hai ví dụ đó, chúng sẽ hoạt động trong Collation không phân biệt chữ hoa chữ thường, nhưng không trả lại gì hoặc lỗi tương ứng, trong Collation phân biệt chữ hoa chữ thường.

Cuối cùng, vì @JonathanFite đủ tốt bụng để nhắc nhở tôi, việc thay đổi DB Collation có thể ảnh hưởng đến các truy vấn liên quan đến các bảng tạm thời. Collation mặc định cho các cột chuỗi trong các bảng tạm thời (không phải biến bảng) là Collation mặc định cho [tempdb](nên giống với [model], đó phải là mặc định Instance, trừ khi có ai đó khôi phục[model]từ một máy chủ có Collation mặc định khác), không phải Collation của Cơ sở dữ liệu cục bộ. Có nghĩa là, mặc dù các bảng tạm thời được tạo mỗi lần và do đó bạn có thể mong đợi chúng hoạt động như "các bảng mới được tạo" với Collation mới, nhưng thực tế chúng sẽ hoạt động như "các bảng hiện có" và sẽ tiếp tục hoạt động như trước đây sự thay đổi đối chiếu. Nếu bạn cần các cột chuỗi trong các bảng tạm thời để sử dụng Collation mới, bạn sẽ cần đặt Collation của chúng một cách rõ ràng bằng cách sử dụng COLLATE DATABASE_DEFAULTtrong các CREATE TABLEcâu lệnh.

Do đó bạn thực sự cần phải làm rất nhiều thử nghiệm!

Nếu bạn muốn thay đổi các cột hiện có thì bạn sẽ cần bỏ các ràng buộc hiện có, đưa ra ALTER TABLE ... ALTER COLUMNvà sau đó tạo lại các ràng buộc. Bạn cũng sẽ cần xây dựng lại các chỉ mục sử dụng bất kỳ cột nào có Collation thay đổi vì thứ tự sắp xếp có thể khác nhau.

Ngoài ra, tốt nhất là không sử dụng Collations bắt đầu bằng SQL_. Thay vì sử dụng Latin1_General_100_CS_AS. Các bộ sưu tập bắt đầu bằng SQL_đã lỗi thời (ngay cả khi không chính thức bị từ chối) kể từ khi SQL Server 2000 được phát hành. Việc xử lý VARCHARdữ liệu / 8 bit của họ đã lỗi thời và không phù hợp với hành vi mới hơn. Thật không may, vì lý do tương thích ngược, Collation mặc định cho các bản cài đặt tiếng Anh Mỹ được sử dụng là SQL_Latin1Collations, như đã lưu ý trong trang MSDN của SQL Server Collations :

Để tương thích ngược, đối chiếu ngôn ngữ tiếng Anh (Hoa Kỳ) mặc định là SQL_Latin1_General *.

Điều này cũng được ghi chú trong biểu đồ Đối chiếu mặc định trong Cài đặt đối chiếu trong trang Cài đặt MSDN (nhấn Control-F và dán vào sql_latin). Tôi tin rằng mặc định này đã thay đổi thành Windows Collation bắt đầu trong SQL Server 2014, nhưng tài liệu, ngay cả đối với thiết lập SQL Server 2016, vẫn trỏ đến trang thiết lập 2008 R2 cho Collations.


Dưới đây là tập lệnh để xem một số khác biệt về hành vi khi thay đổi Đối chiếu của Cơ sở dữ liệu:

USE [master];
GO

IF (DB_ID(N'ChangeDatabaseCollationTest') IS NULL)
BEGIN
    CREATE DATABASE [ChangeDatabaseCollationTest] COLLATE Latin1_General_100_CI_AS;
END;
GO

USE [ChangeDatabaseCollationTest];
GO
-- Current DB Collation: Latin1_General_100_CI_AS

EXEC sp_help 'sys.objects';
-- Collation for [name] = Latin1_General_100_CI_AS

IF ('A' = 'a')
BEGIN
    SELECT 'Case INsensitive comparison works.';
END;
ELSE
BEGIN
    SELECT 'Case INsensitive comparison did NOT work.';
END;
-- Case INsensitive comparison works.


CREATE TABLE dbo.CaseTest_a (ID INT); -- success
SELECT * FROM dbo.CaseTest_A; -- success


CREATE TABLE dbo.CaseTest_A (ID INT); -- error:
-- Msg 2714, Level 16, State 6, Line 5
-- There is already an object named 'CaseTest_A' in the database.




ALTER DATABASE [ChangeCollationTest] COLLATE Latin1_General_100_CS_AS; -- success

IF ('A' = 'a')
BEGIN
    SELECT 'Case INsensitive comparison works.';
END;
ELSE
BEGIN
    SELECT 'Case INsensitive comparison did NOT work.';
END;
-- Case INsensitive comparison did NOT work.


SELECT * FROM dbo.CaseTest_A; -- error:
-- Msg 208, Level 16, State 1, Line 56
-- Invalid object name 'dbo.CaseTest_A'.


CREATE TABLE dbo.CaseTest_A (ID INT); -- success

EXEC sp_help 'sys.objects';
-- Collation for [name] = Latin1_General_100_CS_AS


ALTER DATABASE [ChangeCollationTest] COLLATE Latin1_General_100_CI_AS; -- error:
-- Msg 1505, Level 16, State 1, Line 23
-- The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for
--    the object name 'dbo.sysschobjs' and the index name 'nc1'. The duplicate key
--    value is (0, 1, CaseTest_A).
-- Msg 5072, Level 16, State 1, Line 23
-- ALTER DATABASE failed. The default collation of database 'ChangeCollationTest'
--    cannot be set to Latin1_General_100_CI_AS.

câu trả lời chính xác. Tôi cũng sẽ thêm rằng cần phải cẩn thận khi đối chiếu cơ sở dữ liệu không khớp với đối chiếu máy chủ; TempDB và bằng cách mở rộng, tất cả các bảng tạm thời sử dụng đối chiếu máy chủ theo mặc định. Vì vậy, các thủ tục được lưu trữ hoặc các lệnh khác sử dụng bảng tạm thời có thể kết thúc với một đối chiếu khác với dự kiến.
Jonathan Fite

@JonathanFite Cảm ơn bạn đã đề cập đến điều đó :). Tôi đã thêm thông tin liên quan đến bảng tạm thời, biến bảng, dữ liệu meta cấp độ db, v.v.
Solomon Rutzky

2

Sẽ không có gì xảy ra .. ban đầu. Đối chiếu của cơ sở dữ liệu chỉ là một mặc định được sao chép sang các cột mới khi chúng được tạo. Sau khi tạo xong họ giữ lại đối chiếu đó. Xem sys.columns.collation_name .

Nếu bạn thay đổi đối chiếu cơ sở dữ liệu, sau đó tạo các cột mới, các cột đó có đối chiếu mới. Điều này có thể hoặc không thể đối chiếu tương thích với các cột có sẵn.

Nếu bạn chấp nhận đối chiếu phân biệt chữ hoa chữ thường cho DB thì SQL sẽ phân biệt chữ hoa chữ thường. Tên đối tượng sẽ phải khớp chính xác với chuỗi khai báo. Điều này có thể phá vỡ ứng dụng.

Tôi đã trải qua quá trình này nhiều năm trước. Tôi dường như nhớ rằng tôi phải rõ ràng THAY ĐỔI mỗi cột ký tự trong DB sang đối chiếu mới, và sau đó cập nhật dữ liệu cho thay đổi đối chiếu để khởi động (bảng cập nhật đặt charcol1 = charcol1, charcol2 = charcol2 ...; không phải chuỗi cột không cần thiết). Đây là nhiều phiên bản trước đây vì vậy mọi thứ có thể dễ dàng hơn bây giờ. Tôi đã làm điều đó một lần nữa, tùy thuộc vào kích thước và độ phức tạp, tôi muốn tập lệnh tất cả các đối tượng, chỉnh sửa tệp để xóa các đối chiếu, sau đó xây dựng một DB mới từ đầu và chuyển dữ liệu và quyền, v.v.

Chúc may mắn.


Michael: Bạn không cần phải thực hiện UPDATEtuyên bố vì điều đó thực sự sẽ không thay đổi bất cứ điều gì trong bảng vì Collation chỉ là siêu dữ liệu. Điều đó sẽ chỉ có hiệu lực nếu dữ liệu là VARCHAR/ CHARvà Collation mới được liên kết với một trang Mã khác. Tôi nghi ngờ đó UPDATElà một cách khó khăn để xây dựng lại các chỉ số.
Solomon Rutzky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.