Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Dukungan UTF-8, SQL Server 2012 dan UTF8String UDT

Membuat Jenis Buatan Pengguna khusus melalui SQLCLR adalah tidak , dengan cara apa pun, akan memberi Anda pengganti jenis asli apa pun. Ini sangat berguna untuk membuat sesuatu untuk menangani data khusus. Tetapi string, bahkan dari pengkodean yang berbeda, jauh dari khusus. Mengikuti rute ini untuk data string Anda akan menghancurkan kegunaan sistem Anda, belum lagi kinerja karena Anda tidak akan dapat menggunakan apa pun fungsi string bawaan.

Jika Anda dapat menghemat apa pun di ruang disk, keuntungan itu akan terhapus oleh apa yang akan hilang dalam kinerja keseluruhan. Menyimpan UDT dilakukan dengan membuat serialisasi ke VARBINARY . Jadi untuk melakukan apa saja perbandingan string ATAU penyortiran, di luar perbandingan "biner" / "ordinal", Anda harus mengonversi semua nilai lain, satu per satu, kembali ke UTF-8 untuk kemudian melakukan perbandingan string yang dapat menjelaskan perbedaan linguistik. Dan konversi itu perlu dilakukan di dalam UDT. Ini berarti, seperti tipe data XML, Anda akan membuat UDT untuk menyimpan nilai tertentu, dan kemudian mengekspos metode UDT tersebut untuk menerima parameter string untuk melakukan perbandingan (yaitu Utf8String.Compare(alias.field1) atau, jika mendefinisikan operator untuk tipe tersebut, maka Utf8string1 = Utf8string2 dan memiliki = operator mendapatkan string dalam pengkodean UTF-8 dan kemudian melakukan CompareInfo.Compare() ).

Selain pertimbangan di atas, Anda juga perlu mempertimbangkan bahwa meneruskan nilai bolak-balik melalui API SQLCLR memiliki biaya, terutama bila menggunakan NVARCHAR(MAX) atau VARBINARY(MAX) sebagai lawan dari NVARCHAR(1 - 4000) dan VARBINARY(1 - 4000) masing-masing (jangan bingung membedakan ini sebagai menyiratkan apa pun tentang menggunakan SqlChars / SqlBytes vs SqlString / SqlBinary ).

Terakhir (setidaknya dalam hal menggunakan UDT), jangan mengabaikan fakta bahwa UDT yang ditanyakan adalah kode contoh . Satu-satunya pengujian yang dicatat adalah murni fungsional, tidak ada skalabilitas atau "pelajaran yang didapat setelah bekerja dengan ini selama setahun". Kode uji fungsional ditampilkan di sini di halaman CodePlex berikut dan harus dilihat sebelum melanjutkan dengan keputusan ini karena memberikan gambaran tentang bagaimana Anda perlu menulis kueri Anda untuk berinteraksi dengannya (yang baik untuk bidang atau dua, tapi tidak untuk sebagian besar / semua bidang string):

http://msftengprodsamples.codeplex.com /SourceControl/latest#Kilimanjaro_Trunk/Programmability/CLR/UTF8String/Scripts/Test.sql

Mengingat jumlah kolom dan indeks yang dihitung tetap ditambahkan, apakah ada ruang yang benar-benar disimpan?;-)

Di mana ruang (disk, memori, dll) menjadi perhatian, Anda memiliki tiga opsi:

  1. Jika Anda menggunakan SQL Server 2008 atau yang lebih baru, dan menggunakan Edisi Perusahaan, maka Anda dapat mengaktifkan Kompresi Data . Kompresi Data dapat (tetapi tidak akan "selalu") mengompresi data Unicode di NCHAR dan NVARCHAR bidang. Faktor penentunya adalah:

    1. NCHAR(1 - 4000) dan NVARCHAR(1 - 4000) gunakan Skema Kompresi Standar untuk Unicode , tetapi hanya dimulai di SQL Server 2008 R2, DAN hanya untuk data IN ROW, bukan OVERFLOW! Ini tampaknya lebih baik daripada algoritme kompresi ROW / PAGE biasa.
    2. NVARCHAR(MAX) dan XML (dan saya rasa juga VARBINARY(MAX) , TEXT , dan NTEXT ) data yang IN ROW (tidak keluar baris di halaman LOB atau OVERFLOW) setidaknya dapat dikompresi PAGE, dan mungkin juga ROW dikompresi (tidak yakin tentang yang terakhir ini).
    3. Data OFF ROW, LOB atau OVERLOW =Tanpa Kompresi Untuk Anda!
  2. Jika menggunakan versi yang lebih lama dari 2008 atau tidak pada Edisi Perusahaan, Anda dapat memiliki dua bidang:satu VARCHAR dan satu NVARCHAR . Misalnya, katakanlah Anda menyimpan URL yang sebagian besar adalah semua karakter ASCII dasar (nilai 0 - 127) dan karenanya cocok dengan VARCHAR , tetapi terkadang memiliki karakter Unicode. Skema Anda dapat menyertakan 3 bidang berikut:

      ...
      URLa VARCHAR(2048) NULL,
      URLu NVARCHAR(2048) NULL,
      URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
      CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
                        ([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
                    AND ([URLa] IS NULL OR [URLu] IS NULL))
    );
    

    Dalam model ini Anda hanya PILIH dari [URL] kolom yang dihitung. Untuk menyisipkan dan memperbarui, Anda menentukan bidang mana yang akan digunakan dengan melihat apakah konversi mengubah nilai yang masuk, yang harus berupa NVARCHAR ketik:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
    
  3. Jika Anda memiliki bidang yang seharusnya hanya memiliki karakter yang sesuai dengan Halaman Kode tertentu dari rangkaian karakter ASCII yang Diperluas, gunakan saja VARCHAR .

P.S. Untuk memperjelas hal ini:_SC yang baru Pengumpulan yang diperkenalkan di SQL Server 2012 memungkinkan untuk:

  • fungsi bawaan untuk menangani Karakter Tambahan / Pasangan Pengganti dengan benar, dan
  • aturan linguistik untuk Karakter Tambahan yang digunakan untuk mengurutkan dan membandingkan

Tapi, bahkan tanpa _SC baru Kolasi, Anda masih dapat menyimpan karakter Unicode apa pun ke dalam XML atau N -tipe awalan, dan mengambilnya tanpa kehilangan data. Namun, saat menggunakan Kolasi yang lebih lama (yaitu tidak ada nomor versi dalam namanya), semua Karakter Tambahan disamakan satu sama lain. Anda harus menggunakan _90 dan _100 Kumpulan yang setidaknya memberi Anda perbandingan dan penyortiran titik biner / kode; mereka tidak dapat memperhitungkan aturan linguistik karena mereka tidak memiliki pemetaan khusus dari Karakter Tambahan (dan karenanya tidak memiliki bobot atau aturan normalisasi).

Coba yang berikut ini:

IF (N'𤪆' = N'𤪆') SELECT N'𤪆' AS [TheLiteral], NCHAR(150150) AS [Generated];
IF (N'𤪆' = N'𤪇') SELECT N'𤪇' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'𤪆' COLLATE Tatar_90_CI_AI = N'𤪇' COLLATE Tatar_90_CI_AI)
       SELECT N'𤪇 COLLATE Tatar_90_CI_AI' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'𤪆' = N'?') SELECT N'?';

Dalam DB yang memiliki susunan default yang diakhiri dengan _SC , hanya IF pertama pernyataan akan mengembalikan kumpulan hasil, dan bidang "Dihasilkan" akan menampilkan karakter dengan benar.

Tetapi, jika DB tidak memiliki susunan default yang diakhiri dengan _SC , dan susunannya bukan _90 atau _100 susunan seri, lalu dua IF yang pertama pernyataan mengembalikan kumpulan hasil di mana bidang "Dihasilkan" akan mengembalikan NULL , dan bidang "Literal" muncul dengan benar.

Untuk data Unicode, Collation tidak ada hubungannya dengan penyimpanan fisik.

PERBARUI 2018-10-02

Meskipun ini bukan opsi yang layak, SQL Server 2019 memperkenalkan dukungan asli untuk UTF-8 di VARCHAR / CHAR tipe data. Saat ini ada terlalu banyak bug untuk digunakan, tetapi jika sudah diperbaiki, maka ini adalah opsi untuk beberapa skenario. Silakan lihat posting saya, "Dukungan UTF-8 Asli di SQL Server 2019:Juruselamat atau Nabi Palsu? ", untuk analisis mendetail tentang fitur baru ini.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Server 2008 mengungkapkan kinerja di lingkungan produksi?

  2. Hapus semua spasi dari string di SQL Server

  3. Debezium:Tidak ada LSN maksimum yang tercatat dalam database; harap pastikan bahwa Agen Server SQL sedang berjalan

  4. Bagaimana cara mengubah kueri t-sql ini untuk mengembalikan nilai maksimum untuk nama kolom yang berbeda?

  5. SQL Server JIKA TIDAK ADA Penggunaan?