Trước hết, xin lỗi vì một câu trả lời dài như vậy, vì tôi cảm thấy vẫn còn nhiều sự nhầm lẫn khi mọi người nói về các thuật ngữ như đối chiếu, sắp xếp thứ tự, trang mã, v.v.
Từ BOL :
Các bộ sưu tập trong SQL Server cung cấp các quy tắc sắp xếp, trường hợp và thuộc tính độ nhạy cho dữ liệu của bạn . Các bộ sưu tập được sử dụng với các loại dữ liệu ký tự, chẳng hạn như char và varchar ra lệnh trang mã và các ký tự tương ứng có thể được biểu diễn cho loại dữ liệu đó. Cho dù bạn đang cài đặt phiên bản SQL Server mới, khôi phục bản sao lưu cơ sở dữ liệu hoặc kết nối máy chủ với cơ sở dữ liệu máy khách, điều quan trọng là bạn phải hiểu các yêu cầu về ngôn ngữ, thứ tự sắp xếp và trường hợp và độ nhạy của dữ liệu mà bạn sẽ làm việc với .
Điều này có nghĩa là Collation rất quan trọng vì nó chỉ định các quy tắc về cách sắp xếp và so sánh các chuỗi ký tự của dữ liệu.
Lưu ý: Thông tin thêm về THU THẬP
Bây giờ, trước tiên hãy hiểu sự khác biệt ......
Chạy bên dưới T-SQL:
SELECT *
FROM::fn_helpcollations()
WHERE NAME IN (
'SQL_Latin1_General_CP1_CI_AS'
,'Latin1_General_CI_AS'
)
GO
SELECT 'SQL_Latin1_General_CP1_CI_AS' AS 'Collation'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'CodePage') AS 'CodePage'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'LCID') AS 'LCID'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'ComparisonStyle') AS 'ComparisonStyle'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'Version') AS 'Version'
UNION ALL
SELECT 'Latin1_General_CI_AS' AS 'Collation'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'CodePage') AS 'CodePage'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'LCID') AS 'LCID'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'ComparisonStyle') AS 'ComparisonStyle'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'Version') AS 'Version'
GO
Kết quả sẽ là:
Nhìn vào kết quả trên, sự khác biệt duy nhất là Thứ tự sắp xếp giữa 2 lần đối chiếu. Nhưng điều đó không đúng, bạn có thể thấy lý do tại sao như dưới đây:
Bài kiểm tra 1:
--Clean up previous query
IF OBJECT_ID('Table_Latin1_General_CI_AS') IS NOT NULL
DROP TABLE Table_Latin1_General_CI_AS;
IF OBJECT_ID('Table_SQL_Latin1_General_CP1_CI_AS') IS NOT NULL
DROP TABLE Table_SQL_Latin1_General_CP1_CI_AS;
-- Create a table using collation Latin1_General_CI_AS
CREATE TABLE Table_Latin1_General_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE Latin1_General_CI_AS
)
-- add some data to it
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('Kin_Tester1')
-- Create second table using collation SQL_Latin1_General_CP1_CI_AS
CREATE TABLE Table_SQL_Latin1_General_CP1_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS
)
-- add some data to it
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('Kin_Tester1')
--Now try to join both tables
SELECT *
FROM Table_Latin1_General_CI_AS LG
INNER JOIN Table_SQL_Latin1_General_CP1_CI_AS SLG ON LG.Comments = SLG.Comments
GO
Kết quả kiểm tra 1:
Msg 468, Level 16, State 9, Line 35
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AS" in the equal to operation.
Từ các kết quả trên, chúng ta có thể thấy rằng chúng ta không thể so sánh trực tiếp các giá trị trên các cột với các đối chiếu khác nhau, bạn phải sử dụng COLLATE
để so sánh các giá trị cột.
KIỂM TRA 2:
Sự khác biệt chính là hiệu suất, như Erland Sommarskog chỉ ra tại cuộc thảo luận này trên msdn .
--Clean up previous query
IF OBJECT_ID('Table_Latin1_General_CI_AS') IS NOT NULL
DROP TABLE Table_Latin1_General_CI_AS;
IF OBJECT_ID('Table_SQL_Latin1_General_CP1_CI_AS') IS NOT NULL
DROP TABLE Table_SQL_Latin1_General_CP1_CI_AS;
-- Create a table using collation Latin1_General_CI_AS
CREATE TABLE Table_Latin1_General_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE Latin1_General_CI_AS
)
-- add some data to it
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_tester1')
-- Create second table using collation SQL_Latin1_General_CP1_CI_AS
CREATE TABLE Table_SQL_Latin1_General_CP1_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS
)
-- add some data to it
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_tester1')
--- Tạo chỉ mục trên cả hai bảng
CREATE INDEX IX_LG_Comments ON Table_Latin1_General_CI_AS(Comments)
go
CREATE INDEX IX_SLG_Comments ON Table_SQL_Latin1_General_CP1_CI_AS(Comments)
--- Chạy các truy vấn
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = 'kin_test1'
GO
--- Điều này sẽ có chuyển đổi IMPLICIT
--- Chạy các truy vấn
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = 'kin_test1'
GO
--- Điều này sẽ KHÔNG có chuyển đổi IMPLICIT
Lý do cho chuyển đổi ngầm là bởi vì, tôi có cả đối chiếu cơ sở dữ liệu & máy chủ của mình và cả SQL_Latin1_General_CP1_CI_AS
bảng Table_Latin1_General_CI_AS có cột Nhận xét được xác định như VARCHAR(50)
với COLLATE Latin1_General_CI_AS , do đó, trong quá trình tra cứu, SQL Server phải thực hiện chuyển đổi IMPLICIT.
Bài kiểm tra 3:
Với cùng một thiết lập, bây giờ chúng ta sẽ so sánh các cột varchar với các giá trị nvarchar để xem các thay đổi trong kế hoạch thực hiện.
- chạy truy vấn
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = (SELECT N'kin_test1' COLLATE Latin1_General_CI_AS)
GO
- chạy truy vấn
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = N'kin_test1'
GO
Lưu ý rằng truy vấn đầu tiên có thể thực hiện tìm kiếm Index nhưng phải thực hiện chuyển đổi ngầm định trong khi truy vấn thứ hai thực hiện quét Index, điều này chứng tỏ là không hiệu quả về mặt hiệu suất khi nó sẽ quét các bảng lớn.
Phần kết luận :
- Tất cả các thử nghiệm trên cho thấy rằng có đối chiếu đúng là rất quan trọng đối với trường hợp máy chủ cơ sở dữ liệu của bạn.
SQL_Latin1_General_CP1_CI_AS
là đối chiếu SQL với các quy tắc cho phép bạn sắp xếp dữ liệu cho unicode và không unicode là khác nhau.
- Đối chiếu SQL sẽ không thể sử dụng Index khi so sánh dữ liệu unicode và không unicode như đã thấy trong các thử nghiệm ở trên khi so sánh dữ liệu nvarchar với dữ liệu varchar, nó quét Index và không tìm kiếm.
Latin1_General_CI_AS
là đối chiếu Windows với các quy tắc cho phép bạn sắp xếp dữ liệu cho unicode và không unicode là như nhau.
- Đối chiếu Windows vẫn có thể sử dụng Index (Tìm kiếm chỉ mục trong ví dụ trên) khi so sánh dữ liệu unicode và không unicode nhưng bạn thấy một hình phạt hiệu suất nhẹ.
- Rất khuyến khích đọc câu trả lời của Erland Sommarskog + các mục kết nối mà anh ta đã chỉ.
Điều này sẽ cho phép tôi không gặp vấn đề với các bảng #temp, nhưng có cạm bẫy không?
Xem câu trả lời của tôi ở trên.
Tôi có thể mất bất kỳ chức năng hoặc tính năng nào dưới dạng không sử dụng đối chiếu "hiện tại" của SQL 2008 không?
Tất cả phụ thuộc vào chức năng / tính năng mà bạn đang đề cập đến. Đối chiếu là lưu trữ và sắp xếp dữ liệu.
Còn khi chúng ta chuyển (ví dụ trong 2 năm) từ 2008 sang SQL 2012 thì sao? Tôi sẽ có vấn đề sau đó? Đến một lúc nào đó tôi có bị buộc phải đi đến Latin1_General_CI_AS không?
Không thể chứng từ! Vì mọi thứ có thể thay đổi và luôn luôn tốt khi được đề xuất với đề xuất của Microsoft + bạn cần hiểu dữ liệu của mình và những cạm bẫy mà tôi đã đề cập ở trên. Cũng tham khảo điều này và các mục kết nối này .
Tôi đọc được rằng một số tập lệnh của DBA hoàn thành các hàng cơ sở dữ liệu hoàn chỉnh, và sau đó chạy tập lệnh chèn vào cơ sở dữ liệu với đối chiếu mới - tôi rất sợ và cảnh giác với điều này - bạn có khuyên bạn nên làm điều này không?
Khi bạn muốn thay đổi đối chiếu, thì các kịch bản như vậy rất hữu ích. Tôi đã thấy mình thay đổi đối chiếu cơ sở dữ liệu để khớp với đối chiếu máy chủ nhiều lần và tôi có một số tập lệnh thực hiện khá gọn gàng. Hãy cho tôi biết nếu bạn cần nó.
Tài liệu tham khảo: