Перш за все, вибачте за таку довгу відповідь, оскільки я відчуваю, що все ще існує велика плутанина, коли люди говорять про такі терміни, як зіставлення, порядок сортування, кодова сторінка тощо.
Від BOL :
Збірники на SQL Server надають правила сортування, регістри та чутливості до акцентів для ваших даних . Збірники, які використовуються для типів даних символів, таких як char та varchar, диктують кодову сторінку та відповідні символи, які можуть бути представлені для цього типу даних. Незалежно від того, чи встановлюєте ви новий екземпляр SQL Server, відновлюєте резервне копіювання бази даних або підключаєте сервер до клієнтських баз даних, важливо, щоб ви розуміли вимоги локалі, порядок сортування, чутливість до регістру та акценти даних, з якими ви будете працювати .
Це означає, що Collation є дуже важливим, оскільки він визначає правила щодо сортування та порівняння символьних рядків даних.
Примітка: Більше інформації про КОЛОТАЦІЮ
Тепер давайте спочатку зрозуміємо відмінності ......
Запуск нижче 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
Результати:
Дивлячись на вищезазначені результати, єдина відмінність - це Порядок сортування між двома порівняннями. Але це неправда, яку ви можете зрозуміти, як наведено нижче:
Тест 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
Результати тесту 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.
З наведених вище результатів ми бачимо, що ми не можемо безпосередньо порівнювати значення стовпців з різними зіставленнями, ви повинні використовувати COLLATE
для порівняння значень стовпців.
ТЕСТ 2:
Головною відмінністю є продуктивність, на що Ерланд Соммарського вказує на цій дискусії на 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')
--- Створення індексів на обох таблицях
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)
--- Виконати запити
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = 'kin_test1'
GO
--- Це матиме IMPLICIT конверсію
--- Виконати запити
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = 'kin_test1'
GO
--- Це НЕ матиме ІМПЛІЦІТНОГО перетворення
Причина неявного перетворення тому, що у мене є бази даних і сервер сортування і як SQL_Latin1_General_CP1_CI_AS
і таблиця Table_Latin1_General_CI_AS має стовпець Коментарі , певні як VARCHAR(50)
з COLLATE Latin1_General_CI_AS , тому під час пошуку SQL Server повинен зробити неявне перетворення.
Тест 3:
З тим же налаштуванням ми зараз порівняємо стовпчики varchar зі значеннями nvarchar, щоб побачити зміни в планах виконання.
- запустіть запит
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = (SELECT N'kin_test1' COLLATE Latin1_General_CI_AS)
GO
- запустіть запит
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = N'kin_test1'
GO
Зауважте, що перший запит може виконувати пошук індексу, але повинен виконувати неявне перетворення, тоді як другий виконує сканування індексів, які виявляються неефективними з точки зору продуктивності при скануванні великих таблиць.
Висновок:
- Всі вищеперелічені тести показують, що правильне зіставлення дуже важливо для екземпляра сервера вашої бази даних.
SQL_Latin1_General_CP1_CI_AS
є зіставленням SQL з правилами, що дозволяють сортувати дані за unicode та non-unicode.
- SQL-зіставлення не зможе використовувати Index при порівнянні даних unicode та unicodode, як видно у вищевказаних тестах, що при порівнянні даних nvarchar із варчарськими даними він робить індексне сканування, а не пошук.
Latin1_General_CI_AS
це зіставлення Windows з правилами, що дозволяють сортувати дані для unicode та non-unicode однакові.
- Для порівняння Windows все ще можна використовувати Index (Index search у наведеному вище прикладі) при порівнянні даних unicode та unicodode, але ви бачите невелику штрафну ефективність.
- Настійно рекомендую прочитати відповідь Ерланда Соммарського + підключити елементи, на які він вказав.
Це дозволить мені не мати проблем із таблицями #temp, але чи існують підводні камені?
Дивіться мою відповідь вище.
Чи втратив би я будь-які функціональні можливості чи функції, не використовуючи "поточне" порівняння SQL 2008?
Все залежить від того, які функціональні можливості / функції ви маєте на увазі. Збір - це зберігання та сортування даних.
Що робити, коли ми переходимо (наприклад, через 2 роки) з 2008 року на SQL 2012? У мене тоді будуть проблеми? Мене в якийсь момент змусять перейти до Latin1_General_CI_AS?
Не може поручити! Оскільки все може змінитися і завжди добре узгоджуватись із пропозицією Microsoft + вам потрібно зрозуміти свої дані та підводні камені, про які я згадував вище. Також зверніться до цього та цього підключення елементів.
Я читав, що деякі сценарії DBA заповнюють рядки повних баз даних, а потім запустіть сценарій вставки в базу даних з новим зіставленням - я дуже боюся і з цим насторожуюсь - рекомендуєте ви це робити?
Коли ви хочете змінити зіставлення, такі сценарії корисні. Я виявив, що я багато разів змінював зіставлення баз даних, щоб вони відповідали збірці сервера, і у мене є кілька сценаріїв, що робить це досить акуратно. Дайте мені знати, якщо вам це потрібно.
Список літератури: