Quando `nvarchar / nchar` verrà usato con SQL Server 2019?


11

Con SQL Server 2019 Microsoft introduce il supporto UTF-8 per CHARe VARCHARtipi di dati e dice:

Questa funzione può fornire significativi risparmi di archiviazione, a seconda del set di caratteri in uso. Ad esempio, la modifica di un tipo di dati di colonna esistente con stringhe ASCII da NCHAR (10) a CHAR (10) utilizzando un confronto abilitato per UTF-8, si traduce in una riduzione del 50% circa dei requisiti di archiviazione. Questa riduzione è dovuta al fatto che NCHAR (10) richiede 22 byte per l'archiviazione, mentre CHAR (10) richiede 12 byte per la stessa stringa Unicode.

UTF-8 sembra supportare tutti gli script, quindi in pratica possiamo iniziare a memorizzare i dati Unicode varchare le charcolonne. E come si dice nella documentazione, questo può ridurre la dimensione di tabelle e indici e da lì possiamo ottenere prestazioni ancora migliori, perché viene letta una quantità minore di dati.

Mi chiedo questo significa che possiamo smettere di usare nvarchare le ncharcolonne che implementano UTF-16?

Qualcuno può indicare uno scenario e una ragione, non usare i tipi di dati char con la UTFcodifica e continuare a usare quelli n-chars?


Perché non lo provi e rispondi? Facci anche sapere quanta fatica hai speso per convertire da nvarchar a varchar - quanto tempo hanno impiegato le tabelle alter, e quanto tempo hai impiegato per testare e quali problemi hai riscontrato.
Colin 't Hart,

@ Colin'tHart Se non ci sono problemi noti o considerazioni, sto pianificando di migrare i dati poiché credo che leggere meno dati porterà a prestazioni migliori per il sistema. Per quanto riguarda la conversione, ovviamente ci vorrà del tempo, soprattutto se si hanno indici con la colonna data, devono essere ricostruiti, ma credo che pagherà bene. Ovviamente testerò presto l'impatto sulle prestazioni, solo alla ricerca di eventuali problemi che renderanno superflua la migrazione.
gotqn

Si noti che SQL Server supporta la compressione Unicode per le colonne NVarchar quando si utilizza la compressione PAGE o ROW. docs.microsoft.com/en-us/sql/relational-database/…
David Browne - Microsoft

1
Vale la pena notare che mentre UTF-8 può risparmiare spazio se si memorizzano "dati simili a ASCII", non si tratta di compressione in sé e per sé e non deve essere confuso come tale. Ad esempio, se si memorizzano principalmente nomi cinesi in un database, sarebbe peggio usare i CHARtipi UTF-8 rispetto ai tipi Unicode (con o senza compressione, poiché alla fine i dati devono essere decompressi per essere elaborati). Considera anche che il tipo di stringa nativo di Windows è Unicode, quindi spesso le stringhe UTF-8 devono essere decodificate. I compromessi coinvolti significano che non è probabile che i Ntipi saranno ritirati presto.
Jeroen Mostert,

1
La "app killer" n. 1 per UTF-8 CHARè probabilmente SQL Server su Linux, se il motore ottiene il supporto nativo per l'elaborazione delle stringhe direttamente come UTF-8 - qui UTF-8 è il set di caratteri "nativo" (più o meno) e mantenere le stringhe come UTF-16 è l'alternativa meno efficiente. Inoltre, non sarà male usarlo su Windows in luoghi in cui stai già utilizzando CHAR, ovviamente, poiché le regole di confronto che limitano i caratteri che possono essere memorizzati non sono mai state attraenti.
Jeroen Mostert,

Risposte:


6

questo può ridurre la dimensione di tabelle e indici (enfasi aggiunta)

Riduzione delle dimensioni è possibile solo se la maggior parte dei personaggi sono essenzialmente [space], 0 - 9, A - Z, a - z, e alcuni segni di punteggiatura di base. Al di fuori di quel set specifico di caratteri (in termini di utilizzo pratico, valori ASCII standard da 32 a 126), nella migliore delle ipotesi avrai dimensioni uguali a NVARCHAR/ UTF-16, o in molti casi più grandi.

Sto programmando di migrare i dati poiché credo che leggere meno dati porterà a prestazioni migliori per il sistema.

Stai attento. UTF-8 non è un interruttore magico "ripara tutto". A parità di altre condizioni, sì, leggere di meno migliora le prestazioni. Ma qui "tutte le altre cose" non sono uguali. Anche quando si memorizzano solo caratteri ASCII standard (significato: tutti i caratteri sono 1 byte, quindi richiedono metà dello spazio rispetto alla memorizzazione in NVARCHAR), c'è una leggera penalità prestazionale per l'uso di UTF-8. Credo che il problema sia dovuto al fatto che UTF-8 è una codifica a lunghezza variabile, il che significa che ogni byte deve essere interpretato mentre viene letto per sapere se è un carattere completo o se il byte successivo ne fa parte. Ciò significa che tutte le operazioni su stringa devono iniziare all'inizio e procedere byte per byte. D'altro canto,NVARCHAR / UTF-16 è sempre di 2 byte (anche i caratteri supplementari sono composti da due punti di codice a 2 byte), quindi tutto può essere letto in blocchi di 2 byte.

Nei miei test, anche con solo caratteri ASCII standard, l'archiviazione dei dati come UTF-8 non ha consentito di risparmiare tempo trascorso, ma è stato decisamente peggiore per il tempo della CPU. E questo era senza compressione dei dati, quindi almeno c'era meno spazio su disco utilizzato. Ma, quando si utilizza la compressione, lo spazio richiesto per UTF-8 era solo dell'1% - 1,5% più piccolo. In questo modo, non c'è spazio per risparmiare spazio, ma un tempo CPU maggiore per UTF-8.

Le cose si complicano quando si usa NVARCHAR(MAX)poiché Unicode Compression non funziona con quel tipo di dati, anche se il valore è abbastanza piccolo da essere archiviato in riga. Ma, se i dati sono abbastanza piccoli, dovrebbero comunque trarre vantaggio dalla compressione di riga o di pagina (nel qual caso diventa effettivamente più veloce di UTF-8). Tuttavia, i dati off-row non possono utilizzare alcuna compressione. Tuttavia, rendere la tabella un indice di archivio di colonne in cluster riduce notevolmente le dimensioni di NVARCHAR(MAX)(anche se è ancora leggermente più grande di UTF-8 quando si utilizza un indice di archivio di colonne in cluster).

Qualcuno può indicare uno scenario e un motivo, non usare i tipi di dati char con la codifica UTF

Decisamente. In realtà, non trovo davvero un motivo convincente per usarlo nella maggior parte dei casi. L'unico scenario che beneficia veramente di UTF-8 è:

  1. I dati sono principalmente ASCII standard (valori 0 - 127)
  2. Deve essere Unicode perché potrebbe essere necessario memorizzare un intervallo più ampio di caratteri rispetto a quelli disponibili su una singola pagina di codice a 8 bit (es. VARCHAR)
  3. La maggior parte dei dati è archiviata off-row (quindi la compressione della pagina non funziona nemmeno)
  4. Hai abbastanza dati di cui hai bisogno / desideri ridurre la dimensione per motivi non legati alle prestazioni della query (ad es. Ridurre la dimensione del backup, ridurre il tempo necessario per il backup / ripristino, ecc.)
  5. Non è possibile utilizzare Clustered Columnstore Index (forse l'uso della tabella peggiora le prestazioni in questo caso?)

I miei test mostrano che in quasi tutti i casi, NVARCHAR era più veloce, soprattutto quando c'erano più dati. In effetti, 21k righe con una media di 5k caratteri per riga richiedono 165 MB per UTF-8 e 236 MB per NVARCHARnon compressi. Eppure il tempo NVARCHARera 2 volte più veloce nel tempo trascorso e almeno 2 volte più veloce (a volte più) nel tempo della CPU. Tuttavia, ci sono voluti 71 MB in più sul disco.

A parte questo, non consiglierei ancora di usare UTF-8, almeno a partire da CTP 2, a causa di una varietà di bug che ho trovato in questa funzione.

Per un'analisi dettagliata di questa nuova funzionalità, inclusa una spiegazione delle differenze tra UTF-16 e UTF-8 e un elenco di tali bug, vedere il mio post:

Supporto nativo UTF-8 in SQL Server 2019: Salvatore o Falso profeta?


12

Il supporto UTF-8 offre una nuova serie di opzioni. Un potenziale risparmio di spazio (senza compressione di righe o pagine ) è una considerazione, ma la scelta del tipo e della codifica dovrebbe probabilmente essere fatta principalmente sulla base dei requisiti effettivi per confronto, ordinamento, importazione ed esportazione dei dati .

Potrebbe essere necessario modificare più di quanto si pensi, poiché ad esempio un nchar(1)tipo fornisce due byte di memoria. Questo è sufficiente per memorizzare qualsiasi carattere in BMP (punti codice da 000000 a 00FFFF). Alcuni caratteri in quell'intervallo sarebbero codificati con solo 1 byte in UTF-8 mentre altri richiederebbero 2 o anche 3 byte (vedere questa tabella di confronto per maggiori dettagli). Pertanto, garantire la copertura dello stesso set di caratteri in UTF-8 richiederebbe char(3).

Per esempio:

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);

dà l'errore familiare:

Messaggio 8152, livello 16, stato 30, riga xxx
Dati troncati o binari verrebbero troncati.

O se il flag di traccia 460 è attivo:

Messaggio 2628, livello 16, stato 1, riga xxx
Dati stringa o binari verrebbero troncati nella tabella '@T', colonna 'UTF8'. Valore troncato: ''.

Espandendo la colonna UTF8 char(2)o varchar(2)risolvendo l'errore per 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);

Tuttavia, se fosse ad esempio NCHAR(8364), sarebbe necessario espandere ulteriormente la colonna, a char(3)o varchar(3).

Si noti inoltre che tutte le regole di confronto UTF-8 utilizzano caratteri supplementari, pertanto non funzioneranno con la replica.

A parte tutto il resto, il supporto UTF-8 è solo in anteprima in questo momento, quindi non disponibile per l'uso in produzione.

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.