web-dev-qa-db-fra.com

Comment fonctionne le classement insensible à la casse?

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 explique 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 créé/interrogé efficacement sans se soucier du cas, tout en stockant simultanément les données du cas.

19
cocogorilla

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 d'un index en particulier, les données ont besoin pour être stockées car autrement, cela nécessiterait une recherche dans la table principale à chaque fois pour obtenir la valeur réelle, et il y aurait aucune possibilité d'index de couverture (du moins pas pour les types de chaîne).

Les données, dans la table/l'index clusterisé ou l'index non clusterisé, contiennent pas contient des informations de classement/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 remplacée par une clause COLLATE), 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 trier 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 comparaisons plus rapide, 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

Classements SQL Server (ceux dont le nom commence par SQL_) est la méthode de tri/comparaison antérieure à SQL Server 2000 (même si SQL_Latin1_General_CP1_CI_AS est toujours la valeur par défaut de l'installation sur les systèmes d'exploitation en anglais américain, malheureusement). 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'est-à-dire 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 des caractères comme" Æ "en" [~ # ~] a [~ # ~] "et" [~ # ~] e [~ # ~] ", puis effectue un tri initial afin que les mots sont dans un ordre naturel (comment vous vous attendez à les trouver dans un dictionnaire).
  2. Ensuite, il va caractère par caractère pour déterminer l'égalité basée sur 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). De plus, aucun de ces classements ne prend en charge les caractères supplémentaires (ce qui est logique car ils sont spécifiques à Unicode et ces classements ne s'appliquent qu'aux données non Unicode).

Cette approche s'applique uniquement aux données non Unicode VARCHAR. Chaque combinaison unique de paramètres régionaux, de code la page, la casse et la sensibilité aux accents ont 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 trier et comparer 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

Classements Windows (ceux avec des noms pas commençant par SQL_) est la nouvelle méthode de tri/comparaison (à 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 est pas avec un 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 que plusieurs langues soient triées naturellement 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, la partie "casse" de ce tableau est utilisée, sinon il est ignoré ( donc insensible). Si le classement est sensible à l'accent, alors la partie "diacritique" du tableau est utilisée, sinon il est ignoré (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 a non seulement la même apparence lors du rendu (sauf s'il existe est un problème avec votre police), mais est également considéré comme étant identique à la version à un seul caractère (U + 00FC), à moins d'utiliser 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 tels que " Æ " (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 des 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 du 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 publierai éventuellement un article qui montre les valeurs des clés de tri, comment elles sont calculées, les différences entre les classements SQL Server et Windows, etc. Mais pour l'instant, veuillez voir ma réponse à: Accent Sensitive Sort (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 s'applique aux données NVARCHAR etVARCHAR (même les données non Unicode). Il s'applique aux données non-Unicode VARCHAR 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 existe 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 (qui est malheureusement SQL_Latin1_General_CP1_CI_AS pour les systèmes en anglais américain, donc 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 le [model] DB 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 de CREATE DATABASE en spécifiant la clause COLLATE. 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 clause COLLATE 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: Collations Info
26
Solomon Rutzky

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.

5
mustaccio