Passando da SQL 2005 [SQL_Latin1_General_CP1_CI_AS] al 2008 - perderò tutte le funzionalità utilizzando la "compatibilità con le versioni precedenti"


18

Passiamo da SQL 2005 [Istanza e DB hanno regole di confronto SQL_Latin1_General_CP1_CI_AS] a SQL 2008 [impostazione predefinita Latin1_General_CI_AS].

Ho completato un'installazione di SQL 2008 R2 e utilizzato le Latin1_General_CI_ASregole di confronto predefinite , con il ripristino del database ancora attivo SQL_Latin1_General_CP1_CI_AS. Si sono verificati i problemi esclusi - le tabelle #temp in cui si trovava Latin1_General_CI_ASmentre era in db SQL_Latin1_General_CP1_CI_ASed è qui che sono ora - ho bisogno di consigli sulle insidie ​​ora, per favore.

Durante l'installazione di SQL 2008 R2, ho l'opzione di installazione per l'uso 'SQL Collation, used for backwards compatibility'in cui ho la possibilità di selezionare la stesse regole di confronto del database 2005: SQL_Latin1_General_CP1_CI_AS.

  1. Questo mi permetterà di non avere problemi con le tabelle #temp, ma ci sono insidie?

  2. Vorrei perdere funzionalità o caratteristiche di qualsiasi tipo non utilizzando una raccolta "corrente" di SQL 2008?

  3. Che dire di quando ci spostiamo (ad esempio tra 2 anni) dal 2008 a SQL 2012? Avrò problemi allora?
  4. A un certo punto sarei costretto ad andare Latin1_General_CI_AS?

  5. Ho letto che alcuni script di DBA completano le righe di database completi e quindi eseguono lo script di inserimento nel database con la nuova raccolta - sono molto spaventato e diffidente di questo - consiglieresti di farlo?


2
Se pensi di poter entrare in Hekaton in SQL Server 2014, ecco qualcos'altro che potresti prendere in considerazione per la lettura .
Aaron Bertrand

Risposte:


20

Prima di tutto, mi scuso per una risposta così lunga, poiché ritengo che ci sia ancora molta confusione quando le persone parlano di termini come fascicolazione, ordinamento, tabella codici, ecc.

Da BOL :

Le regole di confronto in SQL Server forniscono regole di ordinamento, case e proprietà di sensibilità dell'accento per i dati . Le regole di confronto utilizzate con tipi di dati carattere come char e varchar determinano la tabella codici e i caratteri corrispondenti che possono essere rappresentati per quel tipo di dati. Che si stia installando una nuova istanza di SQL Server, ripristinando un backup del database o collegando il server ai database client, è importante comprendere i requisiti della locale, l'ordinamento e la sensibilità di maiuscolo e minuscolo dei dati con cui si lavorerà .

Ciò significa che le regole di confronto sono molto importanti in quanto specificano le regole su come ordinare e confrontare le stringhe di caratteri dei dati.

Nota: maggiori informazioni su COLLATIONPROPERTY

Ora vediamo prima le differenze ......

In esecuzione sotto 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

I risultati sarebbero:

inserisci qui la descrizione dell'immagine

Guardando i risultati sopra, l'unica differenza è l'ordinamento tra le 2 regole di confronto, ma questo non è vero, che puoi vedere perché come di seguito:

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

Risultati del test 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.

Dai risultati precedenti possiamo vedere che non possiamo confrontare direttamente i valori su colonne con diverse regole di confronto, che devi usare COLLATE per confrontare i valori di colonna.

TEST 2:

La differenza principale è la prestazione, come sottolinea Erland Sommarskog in questa discussione su 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')

--- Crea indici su entrambe le tabelle

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)

--- Esegui le query

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

--- Questo avrà una conversione IMPLICIT

inserisci qui la descrizione dell'immagine

--- Esegui le query

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

--- Questo NON avrà conversione IMPLICIT

inserisci qui la descrizione dell'immagine

Il motivo della conversione implicita è perché, ho il mio database e le regole di confronto del server sia come SQL_Latin1_General_CP1_CI_ASche nella tabella Table_Latin1_General_CI_AS ha i commenti di colonna definiti come VARCHAR(50)con COLLATE Latin1_General_CI_AS , quindi durante la ricerca SQL Server deve eseguire una conversione IMPLICIT.

Test 3:

Con la stessa configurazione, ora confronteremo le colonne varchar con i valori di nvarchar per vedere le modifiche nei piani di esecuzione.

- esegui la query

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

inserisci qui la descrizione dell'immagine

- esegui la query

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

inserisci qui la descrizione dell'immagine

Si noti che la prima query è in grado di eseguire la ricerca dell'Indice ma deve eseguire la conversione implicita mentre la seconda esegue una scansione dell'Indice che si rivela inefficiente in termini di prestazioni quando eseguirà la scansione di tabelle di grandi dimensioni.

Conclusione :

  • Tutti i test sopra riportati mostrano che avere regole di confronto corrette è molto importante per l'istanza del server di database.
  • SQL_Latin1_General_CP1_CI_AS è un confronto SQL con le regole che consentono di ordinare i dati per Unicode e Non Unicode sono diversi.
  • Le regole di confronto SQL non saranno in grado di utilizzare l'Indice quando si confrontano i dati unicode e non unicode come visto nei test precedenti che, confrontando i dati nvarchar con i dati varchar, esegue la scansione dell'indice e non la ricerca.
  • Latin1_General_CI_AS è un confronto di Windows con le regole che consentono di ordinare i dati per Unicode e Non Unicode.
  • Le regole di confronto di Windows possono comunque utilizzare Index (indice di ricerca nell'esempio sopra) quando si confrontano i dati unicode e non unicode ma si nota una leggera penalità delle prestazioni.
  • Consiglio vivamente di leggere la risposta Erland Sommarskog + gli elementi di connessione che ha indicato.

Questo mi permetterà di non avere problemi con le tabelle #temp, ma ci sono insidie?

Vedi la mia risposta sopra.

Vorrei perdere funzionalità o caratteristiche di qualsiasi tipo non utilizzando una raccolta "corrente" di SQL 2008?

Tutto dipende da quale funzionalità / caratteristiche ti riferisci. Le regole di confronto stanno archiviando e ordinando i dati.

Che dire di quando ci spostiamo (ad esempio tra 2 anni) dal 2008 a SQL 2012? Avrò problemi allora? A un certo punto sarei costretto ad andare su Latin1_General_CI_AS?

Non posso garantire! Poiché le cose potrebbero cambiare ed è sempre bene essere in linea con il suggerimento di Microsoft + devi capire i tuoi dati e le insidie ​​che ho menzionato sopra. Vedere anche questo e questo gli elementi di connessione.

Ho letto che alcuni script di DBA completano le righe di database completi e quindi eseguono lo script di inserimento nel database con la nuova raccolta - sono molto spaventato e diffidente di questo - consiglieresti di farlo?

Quando si desidera modificare le regole di confronto, tali script sono utili. Mi sono ritrovato a cambiare le regole di confronto dei database in modo che corrispondano più volte alle regole di confronto dei server e ho alcuni script che lo rendono abbastanza accurato. Fammi sapere se ne hai bisogno.

Riferimenti :


5

Oltre a ciò che @Kin ha descritto dettagliatamente nella sua risposta , ci sono alcune altre cose da tenere presente quando si cambiano le regole di confronto predefinite del server (ovvero l'istanza) (gli elementi sopra la linea orizzontale sono direttamente rilevanti per le due regole di confronto menzionate nella Domanda; elementi sotto la linea orizzontale sono rilevanti per il generale):

  • SE LA COLLEZIONE PREDEFINITA DEL TUO DATABASE NON STA CAMBIANDO, allora il problema di prestazioni della "conversione implicita" descritto nella risposta di @ Kin non dovrebbe essere un problema poiché i valori letterali di stringa e le variabili locali utilizzano le regole di confronto predefinite del database, non quelle del server. Gli unici impatti per lo scenario in cui viene modificato il confronto a livello di istanza ma non il confronto a livello di database (entrambi descritti in dettaglio di seguito):

    • potenziali conflitti di confronto con tabelle temporanee (ma non variabili di tabella).
    • potenziale codice non funzionante se il casing di variabili e / o cursori non corrisponde alle loro dichiarazioni (ma ciò può avvenire solo se si passa a un'istanza con un confronto binario o sensibile al maiuscolo / minuscolo).
  • Una differenza tra queste due regole di confronto è nel modo in cui ordinano determinati caratteri per i VARCHARdati (ciò non influisce sui NVARCHARdati). Le SQL_regole di confronto non EBCDIC utilizzano ciò che viene chiamato "ordinamento stringa" per i VARCHARdati, mentre tutte le altre regole di confronto e persino i NVARCHARdati per le SQL_regole di confronto non EBCDIC utilizzano ciò che viene chiamato "ordinamento di parole". La differenza è che in "Ordinamento di parole", il trattino -e l'apostrofo '(e forse qualche altro carattere?) Hanno un peso molto basso e sono sostanzialmente ignorati a meno che non ci siano altre differenze nelle stringhe. Per visualizzare questo comportamento in azione, eseguire quanto segue:

    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

    Ritorna:

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

    e:

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

    Mentre "perderai" il comportamento "String Sort", non sono sicuro che lo definirei una "caratteristica". È un comportamento che è stato ritenuto indesiderabile (come evidenziato dal fatto che non è stato portato avanti in nessuna delle regole di confronto di Windows). Tuttavia, si tratta di una netta differenza di comportamento tra le due regole di confronto (di nuovo, solo per i VARCHARdati non EBCDIC ) e si potrebbero avere aspettative di codice e / o clienti basate sul comportamento "String Sort". Ciò richiede il test del codice e, eventualmente, la ricerca per vedere se questo cambiamento nel comportamento potrebbe avere un impatto negativo sugli utenti.

  • Un'altra differenza tra SQL_Latin1_General_CP1_CI_ASe Latin1_General_100_CI_ASè la capacità di fare espansioni sui VARCHARdati (i NVARCHARdati possono già fare questi per la maggior parte delle SQL_regole di confronto), come la gestione æcome se fosse 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;

    Ritorna:

    Latin1_General_100_CI_AS

    L'unica cosa che stai "perdendo" qui non è riuscire a fare queste espansioni. In generale, questo è un altro vantaggio del passaggio a una raccolta Windows. Tuttavia, proprio come con lo spostamento da "String Sort" a "Word Sort", si applica la stessa cautela: si tratta di una differenza di comportamento definita tra le due regole di confronto (di nuovo, solo per i VARCHARdati) e si potrebbe avere codice e / o cliente aspettative basate sul non avere queste mappature. Ciò richiede il test del codice e, eventualmente, la ricerca per vedere se questo cambiamento nel comportamento potrebbe avere un impatto negativo sugli utenti.

    (notato per la prima volta in questa risposta SO da @Zarepheth: SQL Server SQL_Latin1_General_CP1_CI_AS può essere convertito in modo sicuro in Latin1_General_CI_AS? )

  • Le regole di confronto a livello di server vengono utilizzate per impostare le regole di confronto dei database di sistema, che include [model]. Il [model]database viene utilizzato come modello per creare nuovi database, che include [tempdb]all'avvio di ciascun server. Ma, anche con un cambiamento delle regole di confronto a livello di server che modifica le regole di confronto [tempdb], esiste un modo un po 'semplice per correggere le differenze di regole di confronto tra il database che è "corrente" quando CREATE #TempTableviene eseguito e [tempdb]. Quando si creano tabelle temporanee, dichiarare un confronto utilizzando la COLLATEclausola e specificare un confronto di DATABASE_DEFAULT:

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

  • È preferibile utilizzare la versione più recente della raccolta desiderata, se sono disponibili più versioni. A partire da SQL Server 2005, è stata introdotta una serie di regole di confronto "90" e SQL Server 2008 ha introdotto una serie di regole di confronto "100". Puoi trovare queste regole di confronto utilizzando le seguenti query:

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

    Dato che sei su SQL Server 2008 R2, dovresti usare Latin1_General_100_CI_ASinvece di Latin1_General_CI_AS.

  • Una differenza tra le versioni con distinzione tra maiuscole e minuscole di queste particolari regole di confronto (cioè SQL_Latin1_General_CP1_CS_ASe Latin1_General_100_CS_AS) è nell'ordine delle lettere maiuscole e minuscole quando si esegue l'ordinamento con distinzione tra maiuscole e minuscole. Ciò influisce anche sugli intervalli di classi a carattere singolo (ovvero [start-end]) che possono essere utilizzati con l' LIKEoperatore e la PATINDEXfunzione. Le tre query seguenti mostrano questo effetto sia per l'ordinamento che per l'intervallo di caratteri .:

    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

    L'unico modo per ordinare le lettere maiuscole prima delle lettere minuscole (per la stessa lettera) è utilizzare una delle 31 regole di confronto che supporta tale comportamento, ovvero le Hungarian_Technical_*regole di confronto e una manciata di SQL_regole di confronto (che supportano questo comportamento solo per i VARCHARdati ).

  • Meno importante per questo particolare cambiamento, ma comunque buono da sapere poiché avrebbe un impatto se la modifica del server in un confronto binario o con distinzione tra maiuscole e minuscole, è che il confronto a livello di server influisce anche su:

    • nomi di variabili locali
    • Nomi CURSORE
    • Etichette GOTO
    • risoluzione dei nomi del sysnametipo di dati


    Vale a dire, se tu o "il programmatore che hai lasciato di recente" che è apparentemente responsabile di tutti i codici errati ;-) non stavi attento al casing e hai dichiarato una variabile come, @SomethingIDma poi hai fatto riferimento ad essa come in @somethingIdseguito, ciò si spezzerebbe se si passasse a un caso fascicolazione sensibile o binaria. Allo stesso modo, il codice che utilizza il sysnametipo di dati ma si riferisce ad esso come SYSNAME, SysNameo qualcosa di diverso da tutti i minuscoli si interromperà anche se spostato in un'istanza utilizzando un confronto binario sensibile al maiuscolo / minuscolo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.