Переход с SQL 2005 [SQL_Latin1_General_CP1_CI_AS] на 2008 - я потеряю какие-либо функции, используя «обратную совместимость»

18

Мы переходим от SQL 2005 [экземпляр и БД имеют параметры сортировки SQL_Latin1_General_CP1_CI_AS] к SQL 2008 [по умолчанию Latin1_General_CI_AS].

Я завершил установку SQL 2008 R2 и использовал параметры Latin1_General_CI_ASсортировки по умолчанию , при этом восстановление базы данных все еще включено SQL_Latin1_General_CP1_CI_AS. Возникли исключительные проблемы - таблицы #temp, в Latin1_General_CI_ASкоторых находилась БД, SQL_Latin1_General_CP1_CI_ASи именно там я сейчас нахожусь - мне нужен совет по поводу ловушек, пожалуйста.

На установке SQL 2008 R2, у меня есть возможность по установке для использования , 'SQL Collation, used for backwards compatibility'где у меня есть возможность выбрать один и тот же порядок сопоставления в качестве базы данных 2005: SQL_Latin1_General_CP1_CI_AS.

  1. Это позволит мне не иметь проблем с таблицами #temp, но есть ли подводные камни?

  2. Потеряю ли я какую-либо функциональность или какие-либо функции, не используя «текущую» сортировку SQL 2008?

  3. Как насчет того, когда мы перейдем (например, через 2 года) с 2008 на SQL 2012? Будут ли у меня проблемы тогда?
  4. Буду ли я в какой-то момент вынужден идти Latin1_General_CI_AS?

  5. Я прочитал, что некоторые сценарии DBA завершают строки полных баз данных, а затем запускают сценарий вставки в базу данных с новым сопоставлением - я очень напуган и опасаюсь этого - вы бы порекомендовали это сделать?

Питер Питлок
источник
2
Если вы думаете, что можете войти в Hekaton в SQL Server 2014, вот еще кое-что, что вы можете захотеть прочитать .
Аарон Бертран

Ответы:

20

Прежде всего, извиняюсь за такой длинный ответ, так как я чувствую, что все еще существует большая путаница, когда люди говорят о таких терминах, как сортировка, порядок сортировки, кодовая страница и т. Д.

От BOL :

Параметры сортировки в SQL Server предоставляют правила сортировки, свойства чувствительности к регистру и ударения для ваших данных . Параметры сортировки, которые используются с символьными типами данных, такими как char и varchar, определяют кодовую страницу и соответствующие символы, которые могут быть представлены для этого типа данных. Независимо от того, устанавливаете ли вы новый экземпляр SQL Server, восстанавливаете резервную копию базы данных или подключаете сервер к клиентским базам данных, важно, чтобы вы понимали требования к локали, порядок сортировки, а также чувствительность к регистру и акценту данных, с которыми вы будете работать ,

Это означает, что сортировка очень важна, так как она определяет правила сортировки и сравнения символьных строк данных.

Примечание: больше информации о COLLATIONPROPERTY

Теперь давайте сначала понять различия ......

Запуск ниже 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

--- Это будет иметь НЕЗАКОННОЕ преобразование

введите описание изображения здесь

--- Запустить запросы

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 должен выполнить преобразование IMPLICIT.

Тест 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 не смогут использовать индекс при сравнении данных в Юникоде и не-Юникоде, как показано в предыдущих тестах, согласно которым при сравнении данных nvarchar с данными varchar выполняется сканирование индекса, а не поиск.
  • Latin1_General_CI_AS это сопоставление Windows с правилами, которые позволяют сортировать данные для Unicode и Non-Unicode одинаковы.
  • Для сравнения в Windows по-прежнему может использоваться индекс (поиск по индексу в приведенном выше примере) при сравнении данных в Юникоде и не в Юникоде, но вы видите небольшое снижение производительности.
  • Настоятельно рекомендую прочитать Erland Sommarskog answer + connect, на которые он указал.

Это позволит мне не иметь проблем с таблицами #temp, но есть ли подводные камни?

Смотрите мой ответ выше.

Потеряю ли я какую-либо функциональность или какие-либо функции, не используя «текущую» сортировку SQL 2008?

Все зависит от того, какие функции / функции вы имеете в виду. Сортировка - это хранение и сортировка данных.

Как насчет того, когда мы перейдем (например, через 2 года) с 2008 на SQL 2012? Будут ли у меня проблемы тогда? Буду ли я в какой-то момент вынужден перейти на Latin1_General_CI_AS?

Не могу ручаться! Поскольку все может измениться, и всегда хорошо быть в соответствии с предложением Microsoft +, вам необходимо понимать свои данные и подводные камни, о которых я упоминал выше. Также обращайтесь к этому и этому пункту.

Я прочитал, что некоторые сценарии DBA завершают строки полных баз данных, а затем запускают сценарий вставки в базу данных с новым сопоставлением - я очень напуган и опасаюсь этого - вы бы порекомендовали это сделать?

Если вы хотите изменить параметры сортировки, тогда такие сценарии полезны. Я обнаружил, что много раз меняю параметры сортировки баз данных, чтобы они соответствовали параметрам сортировки серверов, и у меня есть несколько сценариев, которые делают это довольно аккуратно. Дайте мне знать, если вам это нужно.

Ссылки :

Кин Шах
источник
5

В дополнение к тому, что @Kin подробно изложил в своем ответе , есть еще несколько вещей, о которых следует помнить при переключении параметров сортировки по умолчанию сервера (т.е. экземпляра) (элементы над горизонтальной линией имеют прямое отношение к двум параметрам сортировки, упомянутым в Вопросе; элементы ниже горизонтальной линии имеют отношение к общему):

  • ЕСЛИ КОЛЛЕКЦИЯ ПО УМОЛЧАНИЮ ВАШЕЙ БАЗЫ ДАННЫХ НЕ ИЗМЕНЯЕТСЯ, то проблема производительности «неявного преобразования», описанная в ответе @ Kin, не должна быть проблемой, поскольку строковые литералы и локальные переменные используют сопоставление по умолчанию для базы данных, а не для сервера. Единственное влияние для сценария, в котором уровень сортировки уровня экземпляра изменяется, но не сортировка уровня базы данных, (оба подробно описаны ниже):

    • потенциальные коллизии конфликтуют с временными таблицами (но не с табличными переменными).
    • потенциальный неработающий код, если регистр переменных и / или курсоров не соответствует их объявлениям (но это может произойти только при переходе к экземпляру с двоичным или чувствительным к регистру сопоставлением).
  • Одно из различий между этими двумя параметрами сортировки заключается в том, как они сортируют определенные символы для VARCHARданных (это не влияет на NVARCHARданные). Для не-EBCDIC SQL_сортировок используется то, что называется «сортировка строк» ​​дляVARCHAR данных , а для всех других сопоставлений и даже NVARCHARданных для сопоставлений без EBCDIC SQL_используется так называемая «сортировка слов». Разница в том, что в «Сортировке слов» тире -и апострофу '(и, может быть, нескольким другим символам?) Дан очень низкий вес, и они по существу игнорируются, если в строках нет других отличий. Чтобы увидеть это поведение в действии, выполните следующее:

    DECLARE @Test TABLE (Col1 VARCHAR(10) NOT NULL);
    INSERT INTO @Test VALUES ('aa');
    INSERT INTO @Test VALUES ('ac');
    INSERT INTO @Test VALUES ('ah');
    INSERT INTO @Test VALUES ('am');
    INSERT INTO @Test VALUES ('aka');
    INSERT INTO @Test VALUES ('akc');
    INSERT INTO @Test VALUES ('ar');
    INSERT INTO @Test VALUES ('a-f');
    INSERT INTO @Test VALUES ('a_e');
    INSERT INTO @Test VALUES ('a''kb');
    
    SELECT * FROM @Test ORDER BY [Col1] COLLATE SQL_Latin1_General_CP1_CI_AS;
    -- "String Sort" puts all punctuation ahead of letters
    
    SELECT * FROM @Test ORDER BY [Col1] COLLATE Latin1_General_100_CI_AS;
    -- "Word Sort" mostly ignores dash and apostrophe

    Возвращает:

    String Sort
    -----------
    a'kb
    a-f
    a_e
    aa
    ac
    ah
    aka
    akc
    am
    ar

    и:

    Word Sort
    ---------
    a_e
    aa
    ac
    a-f
    ah
    aka
    a'kb
    akc
    am
    ar

    Хотя вы «потеряете» поведение «сортировки строк», я не уверен, что назвал бы это «функцией». Это поведение, которое было сочтено нежелательным (о чем свидетельствует тот факт, что оно не было перенесено ни в одно из сопоставлений Windows). Тем не менее, это определенная разница в поведении между двумя (опять сортировки, только для не-EBCDICVARCHAR данных), и вы можете иметь код и / или клиента ожидания , основанные на «Струнный Sort» поведение. Это требует тестирования вашего кода и, возможно, исследования, чтобы увидеть, может ли это изменение поведения оказать какое-либо негативное влияние на пользователей.

  • Еще одно различие между SQL_Latin1_General_CP1_CI_ASи Latin1_General_100_CI_ASзаключается в возможности делать расширения для VARCHARданных ( NVARCHARданные уже могут делать это для большинства SQL_сопоставлений), например, обрабатывать, æкак если бы это было ae:

    IF ('æ' COLLATE SQL_Latin1_General_CP1_CI_AS =
        'ae' COLLATE SQL_Latin1_General_CP1_CI_AS)
    BEGIN
      PRINT 'SQL_Latin1_General_CP1_CI_AS';
    END;
    
    IF ('æ' COLLATE Latin1_General_100_CI_AS =
        'ae' COLLATE Latin1_General_100_CI_AS)
    BEGIN
      PRINT 'Latin1_General_100_CI_AS';
    END;

    Возвращает:

    Latin1_General_100_CI_AS

    Единственное, что вы «теряете» здесь - это невозможность выполнить эти расширения. Вообще говоря, это еще одно преимущество перехода на Windows Collation. Однако, как и при перемещении «Сортировка строк» ​​в «Сортировка слов», применяется то же предостережение: это определенная разница в поведении между двумя параметрами сортировки (опять же, только для VARCHARданных), и у вас может быть код и / или клиент ожидания основаны не на этих отображений. Это требует тестирования вашего кода и, возможно, исследования, чтобы увидеть, может ли это изменение поведения оказать какое-либо негативное влияние на пользователей.

    (впервые отмечено в этом SO-ответе @Zarepheth: может ли SQL Server SQL_Latin1_General_CP1_CI_AS безопасно конвертироваться в Latin1_General_CI_AS? )

  • Сортировка на уровне сервера используется для установки параметров сортировки баз данных системы, в том числе [model]. База [model]данных используется в качестве шаблона для создания новых баз данных, который включает [tempdb]при каждом запуске сервера. Но даже с изменением параметров сортировки на уровне сервера, изменяющих параметры сортировки [tempdb], существует несколько простой способ исправить различия параметров сортировки между базами данных, которые являются «текущими» при CREATE #TempTableвыполнении и [tempdb]. При создании временных таблиц объявите параметры сортировки, используя COLLATEпредложение, и укажите параметры сортировки DATABASE_DEFAULT:

    CREATE TABLE #Temp (Col1 NVARCHAR(40) COLLATE DATABASE_DEFAULT);

  • Лучше всего использовать самую последнюю версию желаемой сортировки, если доступно несколько версий. Начиная с SQL Server 2005, была представлена ​​серия параметров сортировки «90», а в SQL Server 2008 была представлена ​​серия параметров сортировки «100». Вы можете найти эти сопоставления, используя следующие запросы:

    SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]90[_]%'; -- 476
    
    SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]100[_]%'; -- 2686

    Поскольку вы находитесь на SQL Server 2008 R2, вы должны использовать Latin1_General_100_CI_ASвместо Latin1_General_CI_AS.

  • Разница между чувствительными к регистру версиями этих конкретных параметров сортировки (т. Е. SQL_Latin1_General_CP1_CS_ASИ Latin1_General_100_CS_AS) заключается в порядке букв верхнего и нижнего регистра при выполнении сортировки с учетом регистра. Это также влияет на диапазоны односимвольных классов (то есть [start-end]), которые могут использоваться с LIKEоператором и PATINDEXфункцией. Следующие три запроса показывают этот эффект как для сортировки, так и для диапазона символов:

    SELECT tmp.col AS [Upper-case first]
    FROM (VALUES ('a'), ('A'), ('b'), ('B'), ('c'), ('C')) tmp(col)
    WHERE tmp.col LIKE '%[A-C]%' COLLATE SQL_Latin1_General_CP1_CS_AS
    ORDER BY tmp.col COLLATE SQL_Latin1_General_CP1_CS_AS; -- Upper-case first
    
    SELECT tmp.col AS [Lower-case first]
    FROM (VALUES ('a'), ('A'), ('b'), ('B'), ('c'), ('C')) tmp(col)
    WHERE tmp.col LIKE '%[A-C]%' COLLATE Latin1_General_100_CS_AS
    ORDER BY tmp.col COLLATE Latin1_General_100_CS_AS; -- Lower-case first
    
    SELECT tmp.col AS [Lower-case first]
    FROM (VALUES (N'a'), (N'A'), (N'b'), (N'B'), (N'c'), (N'C')) tmp(col)
    WHERE tmp.col LIKE N'%[A-C]%' COLLATE SQL_Latin1_General_CP1_CS_AS
    ORDER BY tmp.col COLLATE SQL_Latin1_General_CP1_CS_AS; -- Lower-case first

    Единственный способ выполнить сортировку в верхнем регистре перед строчными (для одной и той же буквы) - это использовать один из 31 параметров сортировки, который поддерживает такое поведение, а именно: параметры Hungarian_Technical_*сортировки и несколько параметров SQL_сортировки (которые поддерживают это поведение только для VARCHARданных. ).

  • Менее важно для этого конкретного изменения, но все же полезно знать об этом, так как это повлияет, если изменение сервера на двоичную или чувствительную к регистру сортировку, заключается в том, что сортировка на уровне сервера также влияет на:

    • имена локальных переменных
    • Имена курсоров
    • GOTO этикетки
    • разрешение имени sysnameтипа данных


    Это означает, что если вы или «недавно ушедший программист», который, по-видимому, ответственен за весь плохой код ;-), не были внимательны к регистру и объявили переменную как, @SomethingIDа затем обратились к ней как к @somethingIdпозже, это сломалось бы при переходе к делу -чувствительный или бинарный подбор. Точно так же код, который использует sysnameтип данных, но ссылается на него как SYSNAME, SysNameили что-то, отличное от всех строчных букв, также будет поврежден при перемещении в экземпляр с использованием чувствительного к регистру или двоичного сопоставления.

Соломон Руцкий
источник