Pindah dari SQL 2005 [SQL_Latin1_General_CP1_CI_AS] ke 2008 - akankah saya kehilangan fitur apa pun dengan menggunakan 'kompatibilitas mundur'


18

Kami pindah dari SQL 2005 [Instance dan DB memiliki collation of SQL_Latin1_General_CP1_CI_AS] ke SQL 2008 [yang default ke Latin1_General_CI_AS].

Saya menyelesaikan instalasi SQL 2008 R2, dan menggunakan Latin1_General_CI_AScollation default , dengan pemulihan database masih berjalan SQL_Latin1_General_CP1_CI_AS. Masalah yang dikecualikan terjadi - tabel #temp di mana Latin1_General_CI_ASsementara db berada di SQL_Latin1_General_CP1_CI_ASdan di sinilah saya sekarang - saya perlu saran tentang perangkap sekarang.

Pada instalasi SQL 2008 R2, saya memiliki pilihan pada instalasi untuk penggunaan 'SQL Collation, used for backwards compatibility'di mana saya memiliki pilihan untuk memilih pemeriksaan yang sama seperti database 2005: SQL_Latin1_General_CP1_CI_AS.

  1. Ini akan memungkinkan saya untuk tidak memiliki masalah dengan tabel #temp, tetapi apakah ada jebakan?

  2. Apakah saya akan kehilangan fungsionalitas atau fitur apa pun dengan tidak menggunakan susunan SQL 2008 "terkini"?

  3. Bagaimana ketika kita pindah (misalnya dalam 2 tahun) dari 2008 ke SQL 2012? Apakah saya akan memiliki masalah?
  4. Apakah saya akan dipaksa untuk pergi ke suatu titik Latin1_General_CI_AS?

  5. Saya membaca bahwa beberapa skrip DBA melengkapi deretan basis data lengkap, dan kemudian menjalankan skrip sisipkan ke dalam basis data dengan susunan baru - saya sangat takut dan waspada terhadap hal ini - apakah Anda akan merekomendasikan melakukan ini?


2
Jika Anda pikir Anda bisa masuk ke Hekaton di SQL Server 2014, berikut ini hal lain yang mungkin ingin Anda pertimbangkan untuk dibaca .
Aaron Bertrand

Jawaban:


20

Pertama-tama, permintaan maaf atas jawaban yang begitu panjang, karena saya merasa masih ada banyak kebingungan ketika orang berbicara tentang istilah seperti susunan, susunan urutan, halaman kode, dll.

Dari BOL :

Kumpulan di SQL Server menyediakan aturan penyortiran, kasus, dan properti sensitivitas aksen untuk data Anda . Koleksi yang digunakan dengan tipe data karakter seperti char dan varchar mendiktekan halaman kode dan karakter terkait yang dapat direpresentasikan untuk tipe data tersebut. Apakah Anda menginstal contoh baru dari SQL Server, mengembalikan cadangan database, atau menghubungkan server ke database klien, penting bahwa Anda memahami persyaratan lokal, urutan penyortiran, dan case dan sensitivitas aksen dari data yang Anda akan bekerja dengan .

Ini berarti bahwa Collation sangat penting karena menetapkan aturan tentang bagaimana string karakter data diurutkan dan dibandingkan.

Catatan: Info lebih lanjut tentang COLLATIONPROPERTY

Sekarang mari kita pahami perbedaannya ......

Berjalan di bawah 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

Hasilnya adalah:

masukkan deskripsi gambar di sini

Melihat hasil di atas, satu-satunya perbedaan adalah Urutan Urutan antara 2 pemeriksaan. Tapi itu tidak benar, yang dapat Anda lihat mengapa seperti di bawah ini:

Tes 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

Hasil Uji 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.

Dari hasil di atas kita dapat melihat bahwa kita tidak dapat secara langsung membandingkan nilai pada kolom dengan susunan berbeda, Anda harus menggunakan COLLATEuntuk membandingkan nilai kolom.

UJI 2:

Perbedaan utama adalah kinerja, seperti yang ditunjukkan oleh Erland Sommarskog pada diskusi ini di 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')

--- Buat Indeks pada kedua tabel

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)

--- Jalankan kueri

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

--- Ini akan memiliki Konversi IMPLICIT

masukkan deskripsi gambar di sini

--- Jalankan kueri

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

--- Ini TIDAK akan memiliki Konversi IMPLICIT

masukkan deskripsi gambar di sini

Alasan untuk konversi implisit adalah karena, saya memiliki database & Server collation saya sebagai SQL_Latin1_General_CP1_CI_ASdan tabel Table_Latin1_General_CI_AS memiliki kolom Komentar didefinisikan VARCHAR(50)dengan COLLATE Latin1_General_CI_AS , jadi selama pencarian SQL Server harus melakukan konversi IMPLICIT.

Tes 3:

Dengan pengaturan yang sama, sekarang kita akan membandingkan kolom varchar dengan nilai nvarchar untuk melihat perubahan dalam rencana eksekusi.

- jalankan kueri

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

masukkan deskripsi gambar di sini

- jalankan kueri

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

masukkan deskripsi gambar di sini

Perhatikan bahwa permintaan pertama dapat melakukan pencarian Indeks tetapi harus melakukan konversi implisit sementara yang kedua melakukan pemindaian Indeks yang terbukti tidak efisien dalam hal kinerja ketika akan memindai tabel besar.

Kesimpulan:

  • Semua tes di atas menunjukkan bahwa memiliki susunan yang benar sangat penting untuk instance server database Anda.
  • SQL_Latin1_General_CP1_CI_AS SQL collation dengan aturan yang memungkinkan Anda untuk mengurutkan data untuk unicode dan non-unicode berbeda.
  • SQL collation tidak akan dapat menggunakan Indeks ketika membandingkan data unicode dan non-unicode seperti yang terlihat dalam tes di atas bahwa ketika membandingkan data nvarchar dengan data varchar, ia melakukan pemindaian indeks dan tidak mencari.
  • Latin1_General_CI_AS adalah susunan Windows dengan aturan yang memungkinkan Anda untuk mengurutkan data untuk unicode dan non-unicode adalah sama.
  • Windows collation masih dapat menggunakan Index (Index seek dalam contoh di atas) ketika membandingkan data unicode dan non-unicode tetapi Anda melihat sedikit penalti kinerja.
  • Sangat merekomendasikan untuk membaca jawaban Erland Sommarskog + item terhubung yang telah ditunjuknya.

Ini akan memungkinkan saya untuk tidak memiliki masalah dengan tabel #temp, tetapi apakah ada jebakan?

Lihat jawaban saya di atas.

Apakah saya akan kehilangan fungsionalitas atau fitur apa pun dengan tidak menggunakan susunan SQL 2008 "terkini"?

Itu semua tergantung pada fungsi / fitur apa yang Anda maksud. Collation menyimpan dan menyortir data.

Bagaimana ketika kita pindah (misalnya dalam 2 tahun) dari 2008 ke SQL 2012? Apakah saya akan memiliki masalah? Apakah saya akan dipaksa untuk pergi ke Latin1_General_CI_AS?

Tidak bisa menjamin! Karena hal-hal mungkin berubah dan selalu baik untuk sejalan dengan saran Microsoft + Anda harus memahami data Anda dan jebakan yang saya sebutkan di atas. Lihat juga item ini dan item terhubung ini .

Saya membaca bahwa beberapa skrip DBA melengkapi deretan basis data lengkap, dan kemudian menjalankan skrip sisipkan ke dalam basis data dengan susunan baru - saya sangat takut dan waspada terhadap hal ini - apakah Anda akan merekomendasikan melakukan ini?

Saat Anda ingin mengubah susunan, maka skrip seperti itu berguna. Saya menemukan diri saya mengubah susunan basis data agar sesuai dengan susunan server berkali-kali dan saya memiliki beberapa skrip yang melakukannya dengan cukup rapi. Beri tahu saya jika Anda membutuhkannya.

Referensi :


5

Selain apa yang @Kin terinci dalam jawabannya , ada beberapa hal lagi yang harus diperhatikan ketika mengganti susunan standar server (yaitu instance) (item di atas garis horizontal secara langsung relevan dengan dua pemeriksaan yang disebutkan dalam Pertanyaan; item di bawah garis horizontal relevan dengan umum):

  • JIKA KOLABASI DEFAULT DATABASE ANDA TIDAK BERUBAH, maka masalah kinerja "konversi implisit" yang dijelaskan dalam jawaban @ Kin seharusnya tidak menjadi masalah karena string literal dan variabel lokal menggunakan Collation default Database, bukan server. Satu-satunya dampak untuk skenario di mana tingkat instance Collation diubah tetapi tidak tingkat database Collation adalah (keduanya dijelaskan secara rinci di bawah):

    • potensi konflik pemeriksaan dengan tabel sementara (tetapi bukan variabel tabel).
    • kode rusak potensial jika casing variabel dan / atau kursor tidak cocok dengan deklarasi mereka (tetapi ini hanya bisa terjadi jika pindah ke instance dengan collation biner atau case-sensitive).
  • Satu perbedaan antara kedua Collations ini adalah bagaimana mereka mengurutkan karakter tertentu untuk VARCHARdata (ini tidak mempengaruhi NVARCHARdata). SQL_Collations non-EBCDIC menggunakan apa yang disebut "Sort String" untuk VARCHARdata, sedangkan semua Collations lain, dan bahkan NVARCHARdata untuk SQL_Collations non-EBCDIC , menggunakan apa yang disebut "Word Sort". Perbedaannya adalah bahwa dalam "Word Sort", tanda hubung -dan tanda kutip '(dan mungkin beberapa karakter lain?) Diberi bobot yang sangat rendah dan pada dasarnya diabaikan kecuali tidak ada perbedaan lain dalam string. Untuk melihat perilaku ini dalam tindakan, jalankan yang berikut:

    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

    Pengembalian:

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

    dan:

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

    Meskipun Anda akan "kehilangan" perilaku "String Sort", saya tidak yakin bahwa saya akan menyebutnya "fitur". Ini adalah perilaku yang telah dianggap tidak diinginkan (sebagaimana dibuktikan oleh fakta bahwa itu tidak dibawa ke dalam salah satu dari kumpulan Windows). Namun, ini adalah perbedaan perilaku yang pasti antara kedua pemeriksaan (sekali lagi, hanya untuk VARCHARdata non-EBCDIC ), dan Anda mungkin memiliki kode dan / atau harapan pelanggan berdasarkan pada perilaku "String Sort". Ini membutuhkan pengujian kode Anda dan mungkin meneliti untuk melihat apakah perubahan perilaku ini dapat berdampak negatif pada pengguna.

  • Perbedaan lain antara SQL_Latin1_General_CP1_CI_ASdan Latin1_General_100_CI_ASadalah kemampuan untuk melakukan Ekspansi pada VARCHARdata ( NVARCHARdata sudah dapat melakukan ini untuk sebagian besar SQL_Collations), seperti menangani æseolah-olah 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;

    Pengembalian:

    Latin1_General_100_CI_AS

    Satu-satunya hal yang Anda "kehilangan" di sini adalah tidak bisa melakukan ekspansi ini. Secara umum, ini adalah manfaat lain dari pindah ke Windows Collation. Namun, seperti halnya dengan pemindahan "String Sort" ke "Word Sort", kehati-hatian yang sama berlaku: itu adalah perbedaan perilaku yang pasti antara kedua kumpulan (sekali lagi, hanya untuk VARCHARdata), dan Anda mungkin memiliki kode dan / atau pelanggan harapan berdasarkan tidak memiliki pemetaan ini. Ini membutuhkan pengujian kode Anda dan mungkin meneliti untuk melihat apakah perubahan perilaku ini dapat berdampak negatif pada pengguna.

    (pertama kali dicatat dalam jawaban SO ini oleh @Zarepheth: Dapatkah SQL Server SQL_Latin1_General_CP1_CI_AS dikonversi dengan aman ke Latin1_General_CI_AS? )

  • Collation tingkat server digunakan untuk mengatur collation dari database sistem, yang mencakup [model]. Basis [model]data digunakan sebagai templat untuk membuat basis data baru, yang termasuk [tempdb]pada setiap permulaan server. Tetapi, bahkan dengan perubahan susunan tingkat server mengubah susunan [tempdb], ada cara yang agak mudah untuk memperbaiki perbedaan susunan antara database yang "saat ini" ketika CREATE #TempTabledieksekusi dan [tempdb]. Saat membuat tabel sementara, nyatakan sebuah collation menggunakan COLLATEklausa dan tentukan collation dari DATABASE_DEFAULT:

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

  • Cara terbaik adalah menggunakan versi terbaru dari susunan yang diinginkan, jika beberapa versi tersedia. Mulai di SQL Server 2005, serangkaian "90" koleksi diperkenalkan, dan SQL Server 2008 memperkenalkan serangkaian "100" koleksi. Anda dapat menemukan kumpulan ini dengan menggunakan pertanyaan berikut:

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

    Karena Anda berada di SQL Server 2008 R2, Anda harus menggunakan Latin1_General_100_CI_ASbukan Latin1_General_CI_AS.

  • Perbedaan antara versi peka huruf besar dari kumpulan khusus ini (yaitu SQL_Latin1_General_CP1_CS_ASdan Latin1_General_100_CS_AS) adalah dalam urutan huruf besar dan huruf kecil ketika melakukan penyortiran peka terhadap huruf besar-kecil. Ini juga mempengaruhi rentang kelas karakter tunggal (yaitu [start-end]) yang dapat digunakan dengan LIKEoperator dan PATINDEXfungsi. Tiga kueri berikut menunjukkan efek ini untuk pengurutan dan rentang karakter .:

    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

    Satu-satunya cara untuk mendapatkan huruf besar untuk mengurutkan sebelum huruf kecil (untuk huruf yang sama) adalah dengan menggunakan salah satu dari 31 Collations yang mendukung perilaku itu, yang merupakan Hungarian_Technical_*Collations dan beberapa SQL_Collations (yang hanya mendukung perilaku ini untuk VARCHARdata ).

  • Kurang penting untuk perubahan khusus ini, tetapi masih bagus untuk diketahui karena akan berdampak jika mengubah server menjadi gabungan biner atau peka huruf besar kecil, adalah bahwa tingkat tingkatan server juga mempengaruhi:

    • nama variabel lokal
    • Nama CURSOR
    • Label GOTO
    • resolusi nama sysnamedatatype


    Artinya, jika Anda atau "programmer yang pergi baru-baru ini" yang tampaknya bertanggung jawab untuk semua kode buruk ;-) tidak berhati-hati tentang casing dan menyatakan variabel sebagai @SomethingIDtetapi kemudian menyebutnya sebagai @somethingIdnanti, itu akan pecah jika pindah ke case -sensitif atau biner. Demikian pula, kode yang menggunakan sysnamedatatype tetapi menyebutnya sebagai SYSNAME,, SysNameatau sesuatu selain dari semua huruf kecil juga akan rusak jika dipindahkan ke instance menggunakan case-sensitive atau binary collation.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.