Comment fonctionne le classement insensible à la casse?


19

Le type de classement par défaut dans SQL Server permet l'indexation par rapport aux chaînes insensibles à la casse, mais la casse des données est persistante. Comment cela fonctionne-t-il réellement? Je cherche les vrais écrous et boulons, bits et octets, ou une bonne ressource qui l'explique en détail.

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'

Questions sur les classements SQL Server que vous étiez trop timides à poser par Robert Sheldon couvre comment utiliser le classement. Il ne couvre pas le fonctionnement du classement. Je suis intéressé par la façon dont un index peut être efficacement créé / interrogé sans se soucier du cas, tout en stockant simultanément les données du cas.


1
Vous pouvez interroger efficacement (par exemple en utilisant une recherche d'index) des chaînes insensibles à la casse contre un champ sensible à la casse, mais c'est un peu ennuyeux .
John Eisbrener

cocogorilla: veuillez consulter la note n ° 1 que je viens d'ajouter à la fin de ma réponse concernant le classement "par défaut".
Solomon Rutzky

Réponses:


26

indexation par rapport aux chaînes insensibles à la casse, mais le cas des données est conservé. Comment cela fonctionne-t-il réellement?

Ce n'est en fait pas un comportement spécifique à SQL Server, c'est juste comment ces choses fonctionnent en général.

Ainsi, les données sont les données. Si vous parlez spécifiquement d'un index, les données doivent être stockées car sinon, cela nécessiterait une recherche dans la table principale à chaque fois pour obtenir la valeur réelle, et il n'y aurait aucune possibilité d'index de couverture (à pas pour les types de chaînes).

Les données, que ce soit dans l'index de table / cluster ou index non ordonnés en clusters, ne pas contenir aucune collation / informations de tri. Ce sont simplement des données. Le classement (règles locales / culturelles et sensibilités) n'est que des métadonnées attachées à la colonne et utilisées lorsqu'une opération de tri est appelée (sauf si elle est remplacée par unCOLLATE), qui comprendrait la création / reconstruction d'un index. Les règles définies par un classement non binaire sont utilisées pour générer des clés de tri, qui sont des représentations binaires de la chaîne (les clés de tri ne sont pas nécessaires dans les classements binaires). Ces représentations binaires incorporent toutes les règles locales / culturelles et les sensibilités sélectionnées. Les clés de tri sont utilisées pour placer les enregistrements dans leur ordre correct, mais elles ne sont pas elles-mêmes stockées dans l'index ou la table. Ils ne sont pas stockés (au moins je n'ai pas vu ces valeurs dans l'index et on m'a dit qu'ils ne sont pas stockés) parce que:

  1. Ils ne sont pas vraiment nécessaires pour le tri, car ils seraient de toute façon simplement dans le même ordre que les lignes de la table ou de l'index. Mais, l'ordre physique de l'index est juste un tri, pas une comparaison.
  2. Bien que les stocker puisse rendre les comparaisons plus rapides, cela augmenterait également l'index car la taille minimale pour un seul caractère est de 5 octets, et c'est juste un "overhead" (de la structure de clé de tri). La plupart des caractères ont chacun 2 octets, plus 1 octet s'il y a un accent, plus 1 octet s'il s'agit de majuscules. Par exemple, "e" est une clé de 7 octets, "E" et "é" sont tous les deux de 8 octets et "É" est une clé de 9 octets. Par conséquent, cela ne vaut pas la peine de les stocker à la fin.

Il existe deux types de classements: SQL Server et Windows.

serveur SQL

Les classements SQL Server (ceux dont le nom commence par SQL_) sont la méthode de tri / comparaison antérieure à SQL Server 2000 (même si , malheureusement, SQL_Latin1_General_CP1_CI_ASc'est toujours l'installation par défaut sur les systèmes d'exploitation en anglais américain). Dans ce modèle ancien, simpliste et non Unicode, chaque combinaison de paramètres régionaux, de page de codes et des différentes sensibilités reçoit un mappage statique de chacun des caractères de cette page de codes. Chaque caractère se voit attribuer une valeur (c.-à-d. Un poids de tri) pour indiquer comment il correspond aux autres. Les comparaisons dans ce modèle semblent faire une opération en deux passes:

  1. Tout d'abord, il supprime tous les accents (tels que "  ü  " devient "  u  "), développe les caractères comme "  Æ  " en "  A  " et "  E  ", puis effectue un tri initial afin que les mots soient dans un ordre naturel (comme vous le feriez attendez-vous à les trouver dans un dictionnaire).
  2. Ensuite, il va caractère par caractère pour déterminer l'égalité en fonction de ces valeurs sous-jacentes pour chaque caractère. Cette deuxième partie est ce que mustaccio décrit dans sa réponse .

Les seules sensibilités pouvant être ajustées dans ces classements sont: "case" et "accent" ("width", "kana type" et "variation selector" ne sont pas disponibles). En outre, aucun de ces classements ne prend en charge les caractères supplémentaires (ce qui est logique car ceux-ci sont spécifiques à Unicode et ces classements ne s'appliquent qu'aux données non Unicode).

Cette approche s'applique uniquement aux VARCHARdonnées non Unicode . Chaque combinaison unique de paramètres régionaux, de page de codes, de respect de la casse et de sensibilité aux accents possède un "ID de tri" spécifique, que vous pouvez voir dans l'exemple suivant:

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

La seule différence entre les deux premiers classements est la sensibilité à la casse. Le troisième classement est un classement Windows et n'a donc pas de table de mappage statique.

En outre, ces classements doivent être triés et comparés plus rapidement que les classements Windows en raison de la simple recherche de caractères pour trier le poids. Cependant, ces classements sont également beaucoup moins fonctionnels et devraient généralement être évités si possible.

les fenêtres

Les classements Windows (ceux dont le nom ne commence pas par SQL_) sont la méthode de tri / comparaison la plus récente (à partir de SQL Server 2000). Dans ce modèle Unicode plus récent et complexe, chaque combinaison de paramètres régionaux, de page de codes et des différentes sensibilités ne reçoit pas de mappage statique. D'une part, il n'y a pas de pages de codes dans ce modèle. Ce modèle attribue une valeur de tri par défaut à chaque caractère, puis chaque environnement local / culture peut réaffecter des valeurs de tri à n'importe quel nombre de caractères. Cela permet à plusieurs cultures d'utiliser les mêmes personnages de différentes manières. Cela a pour effet de permettre le tri naturel de plusieurs langues en utilisant le même classement si elles n'utilisent pas les mêmes caractères (et si l'une d'entre elles n'a pas besoin de réaffecter de valeurs et peut simplement utiliser les valeurs par défaut).

Les valeurs de tri dans ce modèle ne sont pas des valeurs uniques. Il s'agit d'un tableau de valeurs qui attribuent des poids relatifs à la lettre de base, à tous les signes diacritiques (c'est-à-dire les accents), à la casse, etc. Si le classement est sensible à la casse, alors la partie "casse" de ce tableau est utilisée, sinon il est ignoré ( donc insensible). Si le classement est sensible à l'accent, la partie "diacritique" du tableau est utilisée, sinon elle est ignorée (donc insensible).

Les comparaisons dans ce modèle sont une opération à plusieurs passes:

  1. Tout d'abord, la chaîne est normalisée de sorte que différentes façons de représenter le même caractère seront égales. Par exemple, " ü " pourrait être un seul caractère / point de code (U + 00FC). Vous pouvez également combiner un " u " non accentué (U + 0075) avec un tréma combiné " ̈ " (U + 0308) pour obtenir: " ü ", qui n'a pas seulement la même apparence lors du rendu (sauf en cas de problème avec votre police), mais est également considérée comme la même que la version à un seul caractère (U + 00FC), sauf si vous utilisez un classement binaire (qui compare les octets au lieu des caractères). La normalisation divise le caractère unique en différentes parties, ce qui inclut des extensions pour des caractères comme "  Æ  " (comme indiqué ci-dessus pour les classements SQL Server).
  2. L'opération de comparaison dans ce modèle va caractère par caractère pour chaque sensibilité . Les clés de tri pour les chaînes sont déterminées en appliquant les éléments appropriés de chaque tableau de classement de caractères en fonction des sensibilités qui sont "sensibles". Les valeurs de clé de tri sont organisées par toutes les sensibilités primaires de chaque caractère (le caractère de base), suivies par toutes les sensibilités secondaires (poids diacritique), suivies par le poids de casse de chaque caractère, etc.
  3. Le tri est effectué sur la base des clés de tri calculées. Avec chaque sensibilité regroupée, vous pouvez obtenir un ordre de tri différent de celui que vous obtiendriez avec un classement SQL Server équivalent lorsque vous comparez des chaînes de plusieurs caractères, et des accents sont impliqués, et le classement est sensible aux accents (et encore plus si le classement est également sensible à la casse).

Pour plus de détails sur ce tri, je vais finir par publier un billet qui montre les valeurs, la façon dont elles sont calculées, les différences entre SQL Server et les classements Windows, etc. Mais pour l' instant, s'il vous plaît voir ma clé de tri réponse à: Accent Trier sensible ( veuillez noter que l'autre réponse à cette question est une bonne explication de l'algorithme Unicode officiel, mais SQL Server utilise à la place un algorithme personnalisé, bien que similaire, et même une table de pondération personnalisée).

Toutes les sensibilités peuvent être ajustées dans ces classements: "case", "accent", "width", "kana type" et "variation selector" (à partir de SQL Server 2017, et uniquement pour les classements japonais). En outre, certains de ces classements (lorsqu'ils sont utilisés avec des données Unicode) prennent en charge les caractères supplémentaires (à partir de SQL Server 2012). Cette approche applique à la fois NVARCHAR et VARCHAR les données (même de données non-Unicode). Il s'applique aux VARCHARdonnées non Unicode en convertissant d'abord la valeur en Unicode en interne, puis en appliquant les règles de tri / comparaison.


Notez s'il vous plaît:

  1. Il n'y a pas de classement par défaut universel pour SQL Server. Il y a une installation par défaut qui diffère en fonction des paramètres régionaux / linguistiques actuels du système d'exploitation au moment de l'installation (ce qui est malheureusement SQL_Latin1_General_CP1_CI_ASpour les systèmes en anglais américain, alors veuillez voter pour cette suggestion ). Cela peut être modifié pendant l'installation. Ce classement au niveau de l'instance définit ensuite le classement pour la base de [model]données qui est le modèle utilisé lors de la création de nouvelles bases de données, mais le classement peut être modifié lors de l'exécution CREATE DATABASEen spécifiant la COLLATEclause. Ce classement au niveau de la base de données est utilisé pour les littéraux de variable et de chaîne, ainsi que par défaut pour les nouvelles colonnes (et modifiées!) Lorsque la COLLATEclause n'est pas spécifiée (ce qui est le cas pour l'exemple de code dans la question).
  2. Pour plus d'informations sur les classements / encodages / Unicode, veuillez visiter: Informations sur les classements

5

En règle générale, cela est mis en œuvre à l'aide de tables de classement qui attribuent un certain score à chaque personnage. La routine de tri a un comparateur qui utilise une table appropriée, par défaut ou spécifiée explicitement, pour comparer les chaînes, caractère par caractère, en utilisant leurs scores de classement. Si, par exemple, une table de classement particulière attribue un score de 1 à "a" et de 201 à "A", et un score inférieur dans cette implémentation particulière signifie une priorité plus élevée, alors "a" sera trieur avant "A". Un autre tableau peut attribuer des scores inversés: 201 à "a" et 1 à "A", et l'ordre de tri sera ensuite inversé. Encore un autre tableau pourrait attribuer des scores égaux à "a", "A", "Á" et "Å", ce qui conduirait à une comparaison et un tri insensibles à la casse et à l'accent.

De même, un tel comparateur basé sur une table de classement est utilisé lors de la comparaison d'une clé d'index avec la valeur fournie dans le prédicat.


1
Juste pour info: ces informations ne sont correctes qu'en termes d'utilisation des classements SQL Server (c'est-à-dire ceux dont le nom commence par SQL_) lorsqu'ils sont utilisés sur des VARCHARdonnées. Ce n'est pas exactement vrai pour les NVARCHARdonnées ou les VARCHARdonnées lors de l'utilisation d'un classement Windows (noms ne commençant pas par SQL_).
Solomon Rutzky
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.