Come funzionano le regole di confronto senza distinzione tra maiuscole e minuscole?


19

Il tipo di regole di confronto predefinito in SQL Server consente l'indicizzazione in base a stringhe senza distinzione tra maiuscole e minuscole, ma il caso dei dati è persistente. Come funziona davvero? Sto cercando i veri e propri bulloni, bit e byte, o una buona risorsa che lo spiega in dettaglio.

create table casetest (fruitnames nvarchar(50) not null);
create unique index IX_fruitnames on casetest(fruitnames);

insert into casetest values ('apples');
insert into casetest values ('Pears');
-- this insert fails
insert into casetest values ('pears');

-- this yields 'Pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'

update casetest set fruitnames = 'pears' where fruitnames = 'pEArs'

-- this yields 'pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'

Domande sulle regole di confronto di SQL Server che erano troppo timide da porre da Robert Sheldon descrivono come utilizzare le regole di confronto. Non copre il funzionamento delle regole di confronto. Sono interessato al modo in cui un indice può essere creato / interrogato in modo efficiente senza preoccuparsi del caso, memorizzando contemporaneamente i dati del caso.


1
È possibile eseguire query in modo efficiente (ad esempio utilizzando una ricerca indice) stringhe senza distinzione tra maiuscole e minuscole in un campo sensibile al maiuscolo / minuscolo, ma è un po 'fastidioso .
John Eisbrener,

cocogorilla: vedere la nota n. 1 che ho appena aggiunto alla fine della mia risposta in riferimento al confronto "predefinito".
Solomon Rutzky,

Risposte:


26

indicizzazione in base a stringhe senza distinzione tra maiuscole e minuscole, ma il caso dei dati è persistito. Come funziona davvero?

Questo non è in realtà un comportamento specifico di SQL Server, è solo il modo in cui queste cose funzionano in generale.

Quindi, i dati sono i dati. Se stai parlando di un indice in particolare, i dati devono essere archiviati in quanto altrimenti richiederebbe una ricerca nella tabella principale ogni volta per ottenere il valore effettivo e non ci sarebbe possibilità di un indice di copertura (a almeno non per i tipi di stringa).

I dati, nella tabella / nell'indice cluster o nell'indice non cluster, non contengono alcuna informazione di fascicolazione / ordinamento. Sono semplicemente dati. Le regole di confronto (regole e sensibilità locali / culturali) sono solo metadati allegati alla colonna e utilizzati quando viene chiamata un'operazione di ordinamento (a meno che non venga sovrascritto da unCOLLATEclausola), che includerebbe la creazione / ricostruzione di un indice. Le regole definite da regole di confronto non binarie vengono utilizzate per generare chiavi di ordinamento, che sono rappresentazioni binarie della stringa (le chiavi di ordinamento non sono necessarie nelle regole di confronto binarie). Queste rappresentazioni binarie incorporano tutte le regole locali / culturali e le sensibilità selezionate. Le chiavi di ordinamento vengono utilizzate per posizionare i record nel loro ordine corretto, ma non sono essi stessi memorizzati nell'indice o nella tabella. Non sono memorizzati (almeno non ho visto questi valori nell'indice e mi è stato detto che non sono memorizzati) perché:

  1. Non sono veramente necessari per l' ordinamento poiché sarebbero semplicemente nello stesso ordine delle righe nella tabella o dell'indice comunque. Ma l'ordine fisico dell'indice è solo l'ordinamento, non il confronto.
  2. Mentre memorizzarli potrebbe rendere più rapidi i confronti , aumenterebbe anche l'indice in quanto la dimensione minima per un singolo carattere è di 5 byte, e questo è solo "overhead" (della struttura della chiave di ordinamento). La maggior parte dei caratteri sono 2 byte ciascuno, più 1 byte se c'è un accento, più 1 byte se è maiuscolo. Ad esempio, "e" è una chiave di 7 byte, "E" ed "é" sono entrambi 8 byte e "É" è una chiave di 9 byte. Quindi, non vale la pena conservarli alla fine.

Esistono due tipi di regole di confronto: SQL Server e Windows.

server SQL

Le regole di confronto di SQL Server (quelle che iniziano con i nomi che iniziano con SQL_) sono il metodo di ordinamento / confronto precedente a SQL Server 2000 (anche se purtroppo SQL_Latin1_General_CP1_CI_ASè ancora l'impostazione predefinita dell'installazione sui sistemi operativi inglesi statunitensi). In questo vecchio, semplicistico modello non Unicode, a ciascuna combinazione di impostazioni internazionali, codepage e varie sensibilità viene fornita una mappatura statica di ciascuno dei caratteri in quella codepage. A ciascun personaggio viene assegnato un valore (cioè il peso dell'ordinamento) per indicare come si equivalga agli altri. I confronti in questo modello sembrano eseguire un'operazione a due passaggi:

  1. Innanzitutto, rimuove tutti gli accenti (in modo che "  ü  " diventi "  u  "), espande caratteri come "  Æ  " in "  A  " ed "  E  ", quindi esegue un ordinamento iniziale in modo che le parole siano in un ordine naturale (come si farebbe aspettati di trovarli in un dizionario).
  2. Quindi, si procede carattere per carattere per determinare l'uguaglianza in base a questi valori sottostanti per ciascun personaggio. Questa seconda parte è ciò che il mustaccio sta descrivendo nella sua risposta .

Le uniche sensibilità che possono essere regolate in queste regole di confronto sono: "case" e "accent" ("larghezza", "tipo kana" e "selettore di variazione" non sono disponibili). Inoltre, nessuna di queste regole di confronto supporta caratteri supplementari (il che ha senso in quanto sono specifici di Unicode e queste regole di confronto si applicano solo ai dati non Unicode).

Questo approccio si applica solo ai VARCHARdati non Unicode . Ogni combinazione univoca di impostazioni internazionali, codepage, distinzione tra maiuscole e minuscole e accento sensibile ha un "ID ordinamento" specifico, che puoi vedere nel seguente esempio:

SELECT COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CI_AS', 'SortID'), -- 52
       COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CS_AS', 'SortID'), -- 51
       COLLATIONPROPERTY(N'Latin1_General_100_CI_AS',     'SortID'); --  0

L'unica differenza tra le prime due regole di confronto è la distinzione tra maiuscole e minuscole. Il terzo confronto è un confronto di Windows e quindi non ha una tabella di mapping statica.

Inoltre, queste regole di confronto dovrebbero essere ordinate e confrontate più rapidamente delle regole di confronto di Windows a causa della semplice ricerca di caratteri per ordinare il peso. Tuttavia, queste regole di confronto sono anche molto meno funzionali e dovrebbero generalmente essere evitate, se possibile.

finestre

Le regole di confronto di Windows (quelle con nomi che non iniziano con SQL_) sono il modo più recente (a partire da SQL Server 2000) di ordinare / confrontare. In questo nuovo, complesso, modello Unicode, a ciascuna combinazione di impostazioni internazionali, code page e le varie sensibilità non viene fornita una mappatura statica. Per prima cosa, non ci sono pagine di codice in questo modello. Questo modello assegna un valore di ordinamento predefinito a ciascun carattere, quindi ogni locale / cultura può riassegnare i valori di ordinamento a qualsiasi numero di caratteri. Ciò consente a più culture di utilizzare gli stessi caratteri in modi diversi. Ciò ha l'effetto di consentire l'ordinamento naturale di più lingue utilizzando la stessa fascicolazione se non usano gli stessi caratteri (e se uno di essi non ha bisogno di riassegnare alcun valore e può semplicemente usare i valori predefiniti).

I valori di ordinamento in questo modello non sono valori singoli. Sono una matrice di valori che assegnano pesi relativi alla lettera di base, eventuali segni diacritici (ad es. Accenti), involucro, ecc. Se le regole di confronto fanno distinzione tra maiuscole e minuscole, viene utilizzata la parte "case" di tale matrice, altrimenti viene ignorata ( quindi, insensibile). Se le regole di confronto sono sensibili all'accento, viene utilizzata la parte "diacritica" dell'array, altrimenti viene ignorata (quindi insensibile).

I confronti in questo modello sono un'operazione multi-pass:

  1. Innanzitutto, la stringa viene normalizzata in modo che i vari modi di rappresentare lo stesso carattere siano equivalenti. Ad esempio, " ü " potrebbe essere un singolo carattere / punto di codice (U + 00FC). Puoi anche combinare una " u " non accentata (U + 0075) con una combinazione di diaeresi " ̈ " (U + 0308) per ottenere: " ü ", che non solo ha lo stesso aspetto quando viene visualizzato (a meno che non ci sia un problema con il tuo carattere), ma è anche considerato uguale alla versione a carattere singolo (U + 00FC), a meno che non utilizzi un confronto binario (che confronta i byte anziché i caratteri). La normalizzazione suddivide il singolo carattere nei vari pezzi, che include espansioni per caratteri come "  Æ  " (come notato sopra per le regole di confronto di SQL Server).
  2. L'operazione di confronto in questo modello va carattere per carattere per ogni sensibilità . Le chiavi di ordinamento per le stringhe vengono determinate applicando gli elementi appropriati di ciascun array di valori di confronto dei caratteri in base a quali sensibilità sono "sensibili". I valori della chiave di ordinamento sono organizzati in base a tutte le sensibilità primarie di ciascun carattere (il carattere di base), seguite da tutte le sensibilità secondarie (peso diacritico), seguite dal peso del caso di ciascun carattere e così via.
  3. L'ordinamento viene eseguito in base alle chiavi di ordinamento calcolate. Con ciascuna sensibilità raggruppata insieme, è possibile ottenere un ordinamento diverso rispetto a un confronto SQL Server equivalente quando si confrontano stringhe di più caratteri e sono coinvolti accenti e le regole di confronto sono sensibili all'accento (e ancor più se il confronto è anche sensibile al maiuscolo / minuscolo).

Per maggiori dettagli su questo ordinamento, alla fine pubblicherò un post che mostra i valori della chiave di ordinamento, il modo in cui vengono calcolati, le differenze tra SQL Server e le regole di confronto di Windows, ecc. Ma per ora, vedi la mia risposta a: Accent Sensitive Sort ( si noti che l'altra risposta a questa domanda è una buona spiegazione dell'algoritmo Unicode ufficiale, ma SQL Server utilizza invece un algoritmo personalizzato, sebbene simile, e persino una tabella dei pesi personalizzata).

Tutte le sensibilità possono essere regolate in queste regole di confronto: "case", "accent", "width", "kana type" e "change selector" (a partire da SQL Server 2017 e solo per le regole di confronto giapponesi). Inoltre, alcune di queste regole di confronto (se utilizzate con dati Unicode) supportano caratteri supplementari (a partire da SQL Server 2012). Questo approccio vale sia per NVARCHAR e VARCHAR dati (anche dati non Unicode). Si applica ai VARCHARdati non Unicode convertendo prima il valore in Unicode internamente, quindi applicando le regole di ordinamento / confronto.


Notare che:

  1. Non esistono regole di confronto predefinite universali per SQL Server. Esiste un valore predefinito di installazione che differisce in base alle impostazioni locali / lingua correnti del sistema operativo al momento dell'installazione (che è purtroppo SQL_Latin1_General_CP1_CI_ASper i sistemi inglesi statunitensi, quindi vota per questo suggerimento ). Questo può essere modificato durante l'installazione. Questo confronto a livello di istanza imposta quindi il confronto per il [model]DB che è il modello utilizzato durante la creazione di nuovi DB, ma il confronto può essere modificato durante l'esecuzione CREATE DATABASEspecificando la COLLATEclausola. Questo confronto a livello di database viene utilizzato per valori letterali di variabili e stringhe, nonché per l'impostazione predefinita per le colonne nuove (e modificate!) Quando la COLLATEclausola non è specificata (come nel caso del codice di esempio nella domanda).
  2. Per maggiori informazioni su Raccolte / codifiche / Unicode, visitare: Informazioni sulle fascicoli

5

In genere, questo viene implementato utilizzando tabelle di confronto che assegnano un determinato punteggio a ciascun personaggio. La routine di ordinamento ha un comparatore che utilizza una tabella appropriata, predefinita o specificata esplicitamente, per confrontare stringhe, carattere per carattere, usando i loro punteggi di confronto. Se, ad esempio, una particolare tabella di confronto assegna un punteggio di 1 a "a" e 201 a "A", e un punteggio più basso in questa particolare implementazione significa una precedenza più elevata, allora "a" sarà selezionatore prima di "A". Un'altra tabella potrebbe assegnare punteggi inversi: 201 a "a" e 1 a "A", e l'ordinamento verrà successivamente invertito. Ancora un'altra tabella potrebbe assegnare punteggi uguali a "a", "A", "Á" e "Å", il che porterebbe a un confronto e un ordinamento insensibili a maiuscole e minuscole.

Allo stesso modo, un simile comparatore basato su tabella di confronto viene utilizzato quando si confronta una chiave di indice con il valore fornito nel predicato.


1
Cordiali saluti: queste informazioni sono corrette solo in termini di utilizzo delle regole di confronto di SQL Server (ovvero quelle con nomi che iniziano con SQL_) se utilizzate sui VARCHARdati. Questo non è esattamente vero per i NVARCHARdati o i VARCHARdati quando si utilizza un confronto di Windows (nomi che non iniziano con SQL_).
Solomon Rutzky,
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.