Kapan `nvarchar / nchar` akan digunakan dengan SQL Server 2019?

11

Dengan SQL Server 2019 Microsoft memperkenalkan dukungan UTF-8 untuk CHARdan VARCHARtipe data dan mengatakan:

Fitur ini dapat memberikan penghematan penyimpanan yang signifikan, tergantung pada karakter yang digunakan. Misalnya, mengubah tipe data kolom yang ada dengan string ASCII dari NCHAR (10) ke CHAR (10) menggunakan collation yang diaktifkan UTF-8, diterjemahkan menjadi pengurangan hampir 50% dalam persyaratan penyimpanan. Pengurangan ini karena NCHAR (10) membutuhkan 22 byte untuk penyimpanan, sedangkan CHAR (10) membutuhkan 12 byte untuk string Unicode yang sama.

UTF-8 tampaknya mendukung setiap skrip, jadi pada dasarnya kita dapat mulai menyimpan data varchardan charkolom Unicode . Dan seperti yang dikatakan dalam dokumentasi, ini dapat mengurangi ukuran tabel dan indeks, dan dari sana kita bisa mendapatkan kinerja yang lebih baik, karena jumlah data yang lebih sedikit dibaca.

Saya bertanya-tanya apakah ini berarti kita dapat berhenti menggunakan nvarchardan ncharkolom yang mengimplementasikan UTF-16?

Adakah yang bisa menunjukkan skenario dan alasan, untuk tidak menggunakan tipe data char dengan UTFencoding dan terus menggunakan n-chars?

Gotqn
sumber
Mengapa Anda tidak mengujinya dan melaporkan kembali? Juga beri tahu kami berapa banyak upaya yang Anda keluarkan untuk mengkonversi dari nvarchar ke varchar - berapa lama tabel alter memakan waktu, dan berapa banyak waktu yang Anda habiskan untuk pengujian, dan masalah apa yang Anda temui.
Colin 't Hart
@ Colin'tHart Jika tidak ada masalah atau pertimbangan yang diketahui, saya berencana untuk memigrasikan data karena saya percaya membaca lebih sedikit data akan menghasilkan kinerja yang lebih baik untuk sistem sama sekali. Tentang konversi - tentu saja akan memakan waktu, terutama jika Anda memiliki indeks dengan kolom yang diberikan - mereka perlu dibangun kembali, tetapi saya percaya itu akan membuahkan hasil. Tentu saja saya akan segera menguji dampak kinerja, hanya mencari masalah yang akan membuat migrasi tidak perlu.
Gotqn
Perhatikan bahwa SQL Server mendukung Unicode Compression untuk kolom NVarchar saat menggunakan PAGE atau ROW kompresi. docs.microsoft.com/en-us/sql/relational-databases/…
David Browne - Microsoft
1
Perlu dicatat bahwa sementara UTF-8 dapat menghemat ruang jika Anda menyimpan "data seperti ASCII", itu bukan kompresi dalam dan dari dirinya sendiri, dan tidak boleh salah seperti itu. Misalnya, jika Anda menyimpan terutama nama-nama Cina dalam database, Anda akan lebih buruk menggunakan CHARjenis UTF-8 daripada jenis Unicode (dengan atau tanpa kompresi, karena pada akhirnya data perlu dikompresi untuk diproses). Pertimbangkan juga bahwa tipe string asli Windows adalah Unicode, jadi string UTF-8 sering perlu diterjemahkan. Pengorbanan yang terlibat berarti tidak mungkin bahwa Njenis akan dihentikan dalam waktu dekat.
Jeroen Mostert
1
"Aplikasi pembunuh" # 1 untuk UTF-8 CHARmungkin adalah SQL Server di Linux, jika mesin mendapatkan dukungan asli untuk memproses string secara langsung sebagai UTF-8 - di sini UTF-8 adalah rangkaian karakter "asli" (kurang lebih) dan menjaga string sebagai UTF-16 adalah alternatif yang kurang efisien. Juga tidak ada salahnya untuk menggunakannya pada Windows di tempat-tempat yang sudah Anda gunakan CHAR, tentu saja, karena pengumpulan yang membatasi karakter yang dapat disimpan tidak pernah menarik.
Jeroen Mostert

Jawaban:

6

ini dapat mengurangi ukuran tabel dan indeks (penekanan ditambahkan)

Pengurangan ukuran hanya mungkin jika sebagian dari karakter dasarnya [space], 0 - 9, A - Z, a - z, dan beberapa tanda baca dasar. Di luar itu spesifik set karakter (dalam hal penggunaan praktis, nilai-nilai ASCII standar 32-126), Anda akan di terbaik sama dengan ukuran NVARCHAR/ UTF-16, atau dalam banyak kasus yang lebih besar.

Saya berencana untuk memigrasi data karena saya percaya membaca lebih sedikit data akan menghasilkan kinerja yang lebih baik untuk sistem sama sekali.

Hati-hati. UTF-8 bukanlah saklar ajaib "perbaiki semuanya". Semua hal lain dianggap sama, ya, kurang membaca meningkatkan kinerja. Tetapi di sini "semua hal lain" tidak sama. Bahkan ketika menyimpan hanya karakter ASCII standar (artinya: semua karakter adalah 1 byte, karenanya membutuhkan setengah ruang dibandingkan dengan menyimpan di NVARCHAR), ada sedikit penalti kinerja untuk menggunakan UTF-8. Saya percaya masalah ini karena UTF-8 menjadi pengkodean variabel-panjang, yang berarti bahwa setiap byte harus ditafsirkan ketika dibaca untuk mengetahui apakah itu karakter yang lengkap atau jika byte berikutnya adalah bagian dari itu. Ini berarti bahwa semua operasi string harus dimulai dari awal dan melanjutkan byte-by-byte. Di samping itu,NVARCHAR / UTF-16 selalu 2 byte (bahkan Karakter Tambahan terdiri dari dua Poin Kode 2-byte), sehingga semuanya dapat dibaca dalam potongan 2-byte.

Dalam pengujian saya, bahkan dengan hanya karakter ASCII standar, menyimpan data sebagai UTF-8 tidak memberikan penghematan waktu yang telah berlalu, tetapi jelas lebih buruk untuk waktu CPU. Dan itu tanpa Kompresi Data, jadi setidaknya ada sedikit ruang disk yang digunakan. Tetapi, ketika menggunakan kompresi, ruang yang dibutuhkan untuk UTF-8 hanya 1% - 1,5% lebih kecil. Jadi secara efektif tidak ada penghematan ruang namun waktu CPU lebih tinggi untuk UTF-8.

Hal-hal menjadi lebih rumit ketika menggunakan NVARCHAR(MAX)karena Unicode Compression tidak bekerja dengan tipe data itu, bahkan jika nilainya cukup kecil untuk disimpan dalam baris. Tetapi, jika datanya cukup kecil, seharusnya masih mendapat manfaat dari Row atau Page Compression (dalam hal ini sebenarnya menjadi lebih cepat daripada UTF-8). Namun, data offline tidak dapat menggunakan kompresi apa pun. Namun, membuat tabel Clustered Columnstore Index tidak sangat mengurangi ukuran NVARCHAR(MAX)(bahkan jika itu masih sedikit lebih besar dari UTF-8 saat menggunakan Clustered Columnstore Index).

Adakah yang bisa menunjukkan skenario dan alasan, untuk tidak menggunakan tipe data char dengan pengkodean UTF

Pastinya. Sebenarnya, saya tidak benar-benar menemukan alasan kuat untuk menggunakannya dalam banyak kasus. Satu-satunya skenario yang benar-benar mendapat manfaat dari UTF-8 adalah:

  1. Data sebagian besar adalah ASCII standar (nilai 0 - 127)
  2. Itu harus Unicode karena mungkin perlu menyimpan rentang karakter yang lebih luas daripada yang tersedia pada Halaman Kode 8-bit tunggal (yaitu VARCHAR)
  3. Sebagian besar data disimpan secara offline (sehingga kompresi Halaman tidak berfungsi)
  4. Anda memiliki cukup data yang perlu / ingin Anda kurangi ukurannya untuk alasan kinerja yang tidak diminta (mis. Kurangi ukuran cadangan, kurangi waktu yang diperlukan untuk mencadangkan / memulihkan, dll)
  5. Anda tidak dapat menggunakan Indeks Clumned Columnstore (mungkin penggunaan tabel membuat kinerja lebih buruk dalam kasus ini?)

Pengujian saya menunjukkan bahwa dalam hampir semua kasus, NVARCHAR lebih cepat, terutama ketika ada lebih banyak data. Bahkan, 21k baris dengan rata-rata 5k karakter per baris membutuhkan 165 MB untuk UTF-8 dan 236 MB untuk yang NVARCHARtidak terkompresi. Namun NVARCHAR2x lebih cepat dalam waktu berlalu, dan setidaknya 2x lebih cepat (kadang-kadang lebih) dalam waktu CPU. Namun, itu membutuhkan 71 MB lebih banyak pada disk.

Di luar itu, saya masih tidak akan merekomendasikan menggunakan UTF-8, setidaknya pada CTP 2, karena berbagai bug yang saya temukan di fitur ini.

Untuk analisis terperinci fitur baru ini, termasuk penjelasan tentang perbedaan antara UTF-16 dan UTF-8, dan daftar bug tersebut, silakan lihat posting saya:

Dukungan UTF-8 Asli di SQL Server 2019: Juruselamat atau Nabi Palsu?

Solomon Rutzky
sumber
12

Dukungan UTF-8 memberi Anda satu set opsi baru. Penghematan ruang potensial (tanpa kompresi baris atau halaman ) adalah salah satu pertimbangan, tetapi pilihan jenis dan pengodean mungkin terutama harus dibuat berdasarkan persyaratan aktual untuk perbandingan, pengurutan, impor data, dan ekspor .

Anda mungkin perlu mengubah lebih dari yang Anda pikirkan, karena misalnya suatu nchar(1)tipe menyediakan dua byte penyimpanan. Itu cukup untuk menyimpan karakter apa pun di BMP (titik kode 000000 ke 00FFFF). Beberapa karakter dalam kisaran itu akan dikodekan dengan hanya 1 byte di UTF-8 sementara yang lain akan membutuhkan 2 atau bahkan 3 byte (lihat tabel perbandingan ini untuk lebih jelasnya). Oleh karena itu, memastikan cakupan set karakter yang sama di UTF-8 akan dibutuhkan char(3).

Sebagai contoh:

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 char(1) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

memberikan kesalahan yang umum:

Msg 8152, Level 16, Negara 30, Baris xxx
String atau data biner akan terpotong.

Atau jika trace flag 460 aktif:

Msg 2628, Level 16, Negara 1, Baris xxx
String atau data biner akan terpotong di tabel '@T', kolom 'UTF8'. Nilai terpotong: ''.

Memperluas kolom UTF8 ke char(2)atau varchar(2)mengatasi kesalahan untuk NCHAR(911):

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 varchar(2) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

Namun, jika itu mis. NCHAR(8364), Anda perlu memperluas kolom lebih lanjut, ke char(3)atau varchar(3).

Perhatikan juga bahwa UTF-8 collations semuanya menggunakan karakter tambahan, jadi tidak akan bekerja dengan replikasi.

Selain hal lain, dukungan UTF-8 hanya dalam pratinjau saat ini, jadi tidak tersedia untuk penggunaan produksi.

Paul White 9
sumber