Przechodząc z SQL 2005 [SQL_Latin1_General_CP1_CI_AS] do 2008 r. - czy utracę jakiekolwiek funkcje, używając „kompatybilności wstecznej”

18

Przechodzimy z SQL 2005 [Instancja i DB mają sortowanie SQL_Latin1_General_CP1_CI_AS] do SQL 2008 [domyślnie to Latin1_General_CI_AS].

Ukończyłem instalację SQL 2008 R2 i użyłem domyślnego Latin1_General_CI_ASsortowania z przywracaniem bazy danych SQL_Latin1_General_CP1_CI_AS. Wystąpiły wyjątki - tabele #temp, w których Latin1_General_CI_ASznajdował się czas db SQL_Latin1_General_CP1_CI_ASi to jest miejsce, w którym teraz jestem - potrzebuję teraz porady na temat pułapek.

Na instalacji SQL 2008 R2, mam opcję instalacji do użytku 'SQL Collation, used for backwards compatibility', gdzie mam możliwość wyboru tego samego sortowania jako bazy danych 2005: SQL_Latin1_General_CP1_CI_AS.

  1. Pozwoli mi to nie mieć problemów ze stołami #temp, ale czy są jakieś pułapki?

  2. Czy straciłbym jakąkolwiek funkcjonalność lub funkcje, nie używając „aktualnego” zestawienia SQL 2008?

  3. A co, kiedy przeprowadzimy się (np. Za 2 lata) z 2008 do SQL 2012? Czy wtedy będę miał problemy?
  4. Czy w którymś momencie byłbym zmuszony pójść do Latin1_General_CI_AS?

  5. Przeczytałem, że niektóre skrypty DBA uzupełniają rzędy kompletnych baz danych, a następnie uruchom skrypt wstawiania do bazy danych z nowym zestawieniem - jestem bardzo przestraszony i nieufny - czy poleciłbyś to zrobić?

Peter PitLock
źródło
2
Jeśli uważasz, że możesz dostać się do Hekaton w SQL Server 2014, oto coś innego, co warto rozważyć .
Aaron Bertrand

Odpowiedzi:

20

Przede wszystkim przepraszam za tak długą odpowiedź, ponieważ uważam, że nadal istnieje wiele zamieszania, gdy ludzie mówią o terminach takich jak sortowanie, porządek sortowania, strona kodowa itp.

Z BOL :

Sortowania w SQL Server zapewniają reguły sortowania, wielkość liter i właściwości czułości akcentu dla danych . Zestawienia używane z typami danych znakowych, takimi jak char i varchar, określają stronę kodową i odpowiadające znaki, które mogą być reprezentowane dla tego typu danych. Niezależnie od tego, czy instalujesz nową instancję programu SQL Server, przywracasz kopię zapasową bazy danych, czy łączysz serwer z bazami danych klientów, ważne jest, aby zrozumieć wymagania regionalne, kolejność sortowania oraz wrażliwość na wielkość liter i liter, z którymi będziesz pracować .

Oznacza to, że sortowanie jest bardzo ważne, ponieważ określa zasady sortowania i porównywania ciągów znaków danych.

Uwaga: Więcej informacji na temat COLLATIONPROPERTY

Teraz Najpierw zrozummy różnice ......

Uruchamianie poniżej 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

Wyniki byłyby następujące:

wprowadź opis zdjęcia tutaj

Patrząc na powyższe wyniki, jedyną różnicą jest kolejność sortowania między 2 zestawieniami, ale to nieprawda, co możesz zobaczyć, jak poniżej:

Test 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

Wyniki testu 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.

Z powyższych wyników widzimy, że nie możemy bezpośrednio porównywać wartości w kolumnach z różnymi zestawieniami, musisz użyć COLLATEdo porównania wartości kolumn.

TEST 2:

Główną różnicą jest wydajność, jak wskazuje Erland Sommarskog w tej dyskusji na 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')

--- Utwórz indeksy na obu tabelach

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)

--- Uruchom zapytania

DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = 'kin_test1'
GO

--- Będzie to miało konwersję IMPLICIT

wprowadź opis zdjęcia tutaj

--- Uruchom zapytania

DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = 'kin_test1'
GO

--- NIE będzie to miało IMPLICIT Conversion

wprowadź opis zdjęcia tutaj

Powodem niejawnej konwersji jest to, że mam sortowanie bazy danych i serwera zarówno jako, jak SQL_Latin1_General_CP1_CI_ASi tabela Table_Latin1_General_CI_AS ma kolumnę Komentarze zdefiniowane jak w VARCHAR(50)przypadku COLLATE Latin1_General_CI_AS , więc podczas wyszukiwania SQL Server musi wykonać konwersję IMPLICIT.

Test 3:

Przy takim samym ustawieniu porównamy teraz kolumny varchar z wartościami nvarchar, aby zobaczyć zmiany w planach wykonania.

- uruchom zapytanie

DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments =  (SELECT N'kin_test1' COLLATE Latin1_General_CI_AS)
GO

wprowadź opis zdjęcia tutaj

- uruchom zapytanie

DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = N'kin_test1'
GO

wprowadź opis zdjęcia tutaj

Zauważ, że pierwsze zapytanie jest w stanie wykonać wyszukiwanie indeksu, ale musi wykonać niejawną konwersję, podczas gdy drugie wykonuje skanowanie indeksu, które okazuje się nieefektywne pod względem wydajności podczas skanowania dużych tabel.

Wniosek:

  • Wszystkie powyższe testy pokazują, że prawidłowe sortowanie jest bardzo ważne dla instancji serwera bazy danych.
  • SQL_Latin1_General_CP1_CI_AS to zestawienie SQL z regułami, które pozwalają na sortowanie danych dla kodu Unicode i innego niż Unicode.
  • Sortowanie SQL nie będzie w stanie używać indeksu podczas porównywania danych Unicode i innych niż Unicode, jak widać w powyższych testach, że porównując dane nvarchar z danymi varchar, skanuje indeks i nie szuka.
  • Latin1_General_CI_AS to zestawienie systemu Windows z regułami, które pozwalają ci sortować dane dla Unicode i nie Unicode są takie same.
  • System Windows może nadal korzystać z indeksu (wyszukiwanie indeksu w powyższym przykładzie) podczas porównywania danych unicode i innych niż unicode, ale widzisz niewielki spadek wydajności.
  • Gorąco polecam przeczytanie odpowiedzi Erlanda Sommarskoga + elementy, na które wskazał.

Pozwoli mi to nie mieć problemów ze stołami #temp, ale czy są jakieś pułapki?

Zobacz moją odpowiedź powyżej.

Czy straciłbym jakąkolwiek funkcjonalność lub funkcje, nie używając „aktualnego” zestawienia SQL 2008?

Wszystko zależy od tego, do jakiej funkcjonalności / funkcji się odnosisz. Sortowanie to przechowywanie i sortowanie danych.

A co, kiedy przeprowadzimy się (np. Za 2 lata) z 2008 do SQL 2012? Czy wtedy będę miał problemy? Czy w pewnym momencie byłbym zmuszony przejść do Latin1_General_CI_AS?

Nie mogę ręczyć! Ponieważ wszystko może się zmienić i zawsze dobrze jest być zgodnym z sugestią Microsoftu +, musisz zrozumieć swoje dane i pułapki, o których wspomniałem powyżej. Zapoznaj się także z tym i tymi elementami łączenia.

Przeczytałem, że niektóre skrypty DBA uzupełniają rzędy kompletnych baz danych, a następnie uruchom skrypt wstawiania do bazy danych z nowym zestawieniem - jestem bardzo przestraszony i nieufny - czy poleciłbyś to zrobić?

Jeśli chcesz zmienić sortowanie, przydatne są takie skrypty. Przekonałem się, że wiele razy zmieniam układanie baz danych, aby dopasować układanie na serwerze i mam kilka skryptów, które robią to całkiem nieźle. Daj mi znać, jeśli będziesz tego potrzebować.

Bibliografia :

Kin Shah
źródło
5

Oprócz tego, co @Kin szczegółowo opisał w swojej odpowiedzi , należy pamiętać o kilku innych rzeczach przy przełączaniu domyślnego sortowania serwera (tj. Instancji) (elementy powyżej linii poziomej są bezpośrednio związane z dwoma zestawieniami wymienionymi w pytaniu; elementy poniżej linii poziomej odnoszą się do ogólnych):

  • JEŚLI DOMYŚLNA KOLACJA BAZY DANYCH NIE JEST ZMIENIONA, to problem wydajności „niejawnej konwersji” opisany w odpowiedzi @ Kin nie powinien stanowić problemu, ponieważ literały łańcuchowe i zmienne lokalne używają domyślnego sortowania bazy danych, a nie serwera. Jedyny wpływ na scenariusz, w którym zmienia się sortowanie na poziomie instancji, ale nie sortowanie na poziomie bazy danych (oba opisano szczegółowo poniżej):

    • potencjalne konflikty zestawień z tabelami tymczasowymi (ale nie zmiennymi tabelowymi).
    • potencjalnie uszkodzony kod, jeśli obudowa zmiennych i / lub kursorów nie zgadza się z ich deklaracjami (ale może się to zdarzyć tylko w przypadku przejścia do instancji z sortowaniem binarnym lub z rozróżnianiem wielkości liter).
  • Jedną różnicą między tymi dwoma zestawieniami jest sposób sortowania określonych znaków dla VARCHARdanych (nie wpływa to na NVARCHARdane). Zestawienia niebędące EBCDIC SQL_używają do VARCHARdanych tak zwanego „sortowania ciągów” , podczas gdy wszystkie inne zestawienia, a nawet NVARCHARdane dla zestawień niebędących EBCDIC SQL_, używają tak zwanego „sortowania słów”. Różnica polega na tym, że w „Sortowaniu słów” myślnik -i apostrof '(a może kilka innych znaków?) Mają bardzo małą wagę i są zasadniczo ignorowane, chyba że występują inne różnice w łańcuchach. Aby zobaczyć to zachowanie w działaniu, uruchom następujące polecenie:

    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

    Zwroty:

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

    i:

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

    Chociaż „stracisz” zachowanie „Sortowanie ciągów”, nie jestem pewien, czy nazwałbym to „funkcją”. Jest to zachowanie uznane za niepożądane (o czym świadczy fakt, że nie zostało przeniesione do żadnej z zestawów Windows). Jest to jednak wyraźna różnica w zachowaniu między dwoma zestawieniami (ponownie, tylko w przypadku VARCHARdanych niebędących danymi EBCDIC ), i możesz mieć kod i / lub oczekiwania klienta oparte na zachowaniu „Sortowanie ciągów”. Wymaga to przetestowania kodu i ewentualnie zbadania, czy zmiana zachowania może mieć negatywny wpływ na użytkowników.

  • Kolejną różnicą pomiędzy SQL_Latin1_General_CP1_CI_ASi Latin1_General_100_CI_ASjest możliwość zrobienia Rozszerzenia na VARCHARdanych ( NVARCHARdane te mogą już zrobić dla większości SQL_Konfrontacje), takie jak obsługa æ, jakby to było 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;

    Zwroty:

    Latin1_General_100_CI_AS

    Jedyną rzeczą, którą są „utratą” jest tu nie jest w stanie wykonać tych rozszerzeń. Ogólnie rzecz biorąc, jest to kolejna zaleta przejścia na sortowanie systemu Windows. Jednak, podobnie jak w przypadku przenoszenia „Sortowanie według ciągów” do „Sortowania według słów”, obowiązuje ta sama uwaga: jest to wyraźna różnica w zachowaniu między dwoma zestawieniami (ponownie, tylko dla VARCHARdanych), i możesz mieć kod i / lub klienta oczekiwania oparte na braku tych mapowań. Wymaga to przetestowania kodu i ewentualnie zbadania, czy zmiana zachowania może mieć negatywny wpływ na użytkowników.

    (po raz pierwszy odnotowany w tej SO odpowiedzi przez @Zarepheth: Czy SQL Server SQL_Latin1_General_CP1_CI_AS można bezpiecznie przekonwertować na Latin1_General_CI_AS? )

  • Sortowanie na poziomie serwera służy do ustawiania sortowania systemowych baz danych, które obejmuje [model]. Baza [model]danych jest używana jako szablon do tworzenia nowych baz danych, które obejmują [tempdb]przy każdym uruchomieniu serwera. Ale nawet przy zmianie sortowania na poziomie serwera zmieniającej sortowanie [tempdb], istnieje dość prosty sposób na poprawienie różnic sortowania między bazą danych, która jest „aktualna”, kiedy CREATE #TempTablejest wykonywana, i [tempdb]. Tworząc tabele tymczasowe, zadeklaruj sortowanie za pomocą COLLATEklauzuli i określ sortowanie DATABASE_DEFAULT:

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

  • Najlepiej jest użyć najnowszej wersji żądanego sortowania, jeśli dostępnych jest wiele wersji. Począwszy od SQL Server 2005, wprowadzono serię „90” zestawień, a SQL Server 2008 wprowadził serię „100” zestawień. Możesz znaleźć te zestawienia, korzystając z następujących zapytań:

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

    Ponieważ korzystasz z SQL Server 2008 R2, powinieneś użyć Latin1_General_100_CI_ASzamiast Latin1_General_CI_AS.

  • Różnica między wersjami tych konkretnych zestawień (tzn. SQL_Latin1_General_CP1_CS_ASI Latin1_General_100_CS_AS) z rozróżnianiem małych i dużych liter polega na kolejności wielkich i małych liter podczas sortowania z rozróżnianiem małych i wielkich liter. Wpływa to również na jednoznakowe zakresy klas (tj. [start-end]), Które mogą być używane z LIKEoperatorem i PATINDEXfunkcją. Poniższe trzy zapytania pokazują ten efekt zarówno dla sortowania, jak i zakresu znaków:

    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

    Jedynym sposobem na sortowanie wielkich liter przed małymi literami (dla tej samej litery) jest użycie jednego z 31 zestawień, które obsługują to zachowanie, czyli Hungarian_Technical_*zestawień i garści SQL_zestawień (które obsługują tylko to zachowanie dla VARCHARdanych ).

  • Mniej ważne dla tej konkretnej zmiany, ale nadal warto o niej wiedzieć, ponieważ zmiana serwera na sortowanie binarne lub z rozróżnianiem wielkości liter ma wpływ, ponieważ sortowanie na poziomie serwera wpływa również na:

    • lokalne nazwy zmiennych
    • Nazwy KURSORA
    • Etykiety GOTO
    • rozpoznawanie nazw sysnametypu danych


    Oznacza to, że jeśli ty lub „programista, który ostatnio opuścił”, który jest najwyraźniej odpowiedzialny za cały zły kod ;-) nie byłeś ostrożny z obudową i zadeklarował zmienną jako, @SomethingIDale później nazwał ją zmienną @somethingIdpóźniej, to by się zepsuło, gdybyś przeniósł się do sprawy -wrażliwe lub binarne sortowanie. Podobnie kod, który używa sysnametypu danych, ale odnosi się do niego jako SYSNAME, SysNamelub coś innego niż wszystkie małe litery również ulegnie awarii, jeśli zostanie przeniesiony do instancji za pomocą sortowania z rozróżnianiem wielkości liter lub binarnym.

Solomon Rutzky
źródło