Lors de la création d'une base de données de test pour une autre question que j'ai posée plus tôt, je me suis souvenu qu'une clé primaire pouvait être déclarée NONCLUSTERED
Quand utiliseriez-vous une clé primaire NONCLUSTERED
par opposition à une clé primaire CLUSTERED
?
Merci d'avance
La question n'est pas "quand le PK doit-il être NC", mais à la place vous devez vous demander "quelle est la clé appropriée pour l'index clusterisé"?
Et la réponse dépend vraiment de comment interrogez-vous les données. L'index cluster a un avantage sur tous les autres index: puisqu'il inclut toujours toutes les colonnes, il est toujours couvrant. Par conséquent, les requêtes qui peuvent tirer parti de l'index cluster n'ont certainement pas besoin d'utiliser des recherches pour satisfaire certaines des colonnes et/ou prédicats projetés.
Une autre pièce du puzzle est comment utiliser un index? Il existe trois modèles typiques:
Donc, si vous analysez votre charge attendue (les requêtes) et découvrez qu'un grand nombre de requêtes utiliseraient un index particulier car elles utilisent un certain modèle d'accès qui bénéficie d'un index, il est logique de proposer cet index comme index cluster.
Un autre facteur encore est que la clé d'index cluster est la clé de recherche utilisée par tous les indices non cluster et donc une large clé d'index cluster crée un effet d'entraînement et élargit tous les indices non cluster et moyenne d'indices larges plus de pages, plus d'E/S, plus de mémoire, moins de qualité.
Un bon index cluster est stable, il ne change pas pendant la durée de vie de l'entité, car un changement dans les valeurs de clé d'index cluster signifie que la ligne doit être supprimée et réinsérée.
Et un bon index clusterisé croît dans un ordre non aléatoire (chaque valeur de clé nouvellement insérée est plus grande que la valeur précédente) afin d'éviter les fractionnements de page et la fragmentation (sans déconner avec FILLFACTOR
s).
Alors maintenant que nous savons ce qu'est une bonne clé d'index cluster, la clé primaire (qui est une propriété logique de modélisation des données) correspond-elle aux exigences? Si oui, le PK doit être mis en cluster. Si non, le PK doit être non clusterisé.
Pour donner un exemple, considérons un tableau des faits commerciaux. Chaque entrée a un ID qui est la clé primaire. Mais la grande majorité des requêtes demandent des données entre une date et une autre date, donc la meilleure clé d'index cluster serait les ventes date, pas le ID . Un autre exemple d'avoir un index cluster différent de la clé primaire est une clé de sélectivité très faible, comme une "catégorie" ou un "état", une clé avec seulement très peu de valeurs distinctes. Avoir une clé d'index cluster avec cette clé de faible sélectivité comme clé la plus à gauche, par ex. (state, id)
, a souvent du sens en raison des analyses de plages qui recherchent toutes les entrées dans un "état" particulier.
Une dernière remarque sur la possibilité d'une clé primaire non clusterisée sur un tas (c'est-à-dire qu'il n'y a pas du tout d'index clusterisé). Cela peut être un scénario valide, la raison typique est lorsque les performances d'insertion en bloc sont critiques, car les tas ont un débit d'insertion en bloc significativement meilleur par rapport aux indices en cluster.
La raison fondamentale d'utiliser les index cluster est indiquée sur Wikipedia :
Le regroupement modifie le bloc de données dans un certain ordre distinct pour correspondre à l'index, ce qui entraîne le stockage des données de ligne dans l'ordre. Par conséquent, un seul index cluster peut être créé sur une table de base de données donnée. Les indices groupés peuvent augmenter considérablement la vitesse globale de récupération, mais généralement uniquement lorsque les données sont accessibles séquentiellement de la même manière ou ordre inverse de l'index cluster , ou lorsqu'une plage d'éléments est sélectionnée.
Disons que j'ai une table de personnes, et ces personnes ont une colonne Pays et une clé primaire unique. C'est un tableau démographique, donc ce sont les seules choses qui me tiennent à cœur; quel pays et combien de personnes uniques sont liées à ce pays.
Je suis donc seulement susceptible de CHOISIR OERE ou COMMANDER PAR la colonne Pays; un index clusterisé sur la clé primaire ne me fait aucun bien, je n'accède pas à ces données par PK, j'y accède par cette autre colonne. Étant donné que je ne peux avoir qu'un seul index cluster sur une table, déclarer mon PK comme cluster m'empêcherait d'utiliser un index cluster sur pays.
De plus, voici un bon article sur Clustered vs Nonclustered Indexes , il s'avère que les index clusterisés ont causé des problèmes de performances d'insertion dans SQL Server 6.5 (ce qui, du moins espérons-le, n'est pas pertinent pour la plupart d'entre nous ici).
Si vous placez un index cluster sur une colonne IDENTITY, toutes vos insertions se produiront sur la dernière page du tableau - et cette page est verrouillée pendant la durée de chaque IDENTITY. Ce n'est pas grave ... sauf si vous avez 5000 personnes qui veulent toutes la dernière page. Ensuite, vous avez beaucoup de conflits pour cette page
Notez que ce n'est pas le cas dans les versions ultérieures.
Si votre clé primaire est du UNIQUEIDENTIFIER
, assurez-vous de spécifier qu'il s'agit du NONCLUSTERED
. Si vous le faites en cluster, chaque insert devra faire un tas de brassage des enregistrements pour insérer la nouvelle ligne dans la position correcte. Cela améliorera les performances.
Un exemple très courant:
Customer
table avec CustomerID
comme CLUSTERED PRIMARY KEY
OrderID (PK), CustomerID, OrderDate
et quelques autres colonnesOrderPositions
avec OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
Bien sûr, "cela dépend" est - comme presque toujours - la bonne réponse, mais la plupart des applications (pas les BI-Reports) fonctionneront en fonction du client (par exemple, vous vous connectez en tant que client 278 sur le site Web et cliquez sur "Mes commandes" ou le vendeur répertorie toutes les commandes pour le client 4569 ou votre routine de facturation résumera toutes les commandes pour le client 137).
Dans ce cas, cela n'aurait pas beaucoup de sens de regrouper la table par OrderID
. Oui, vous aurez des requêtes sous la forme SELECT ... WHERE OrderId = ?
Pour répertorier les détails de la commande, mais ce serait généralement une recherche d'index courte et bon marché (3 lectures).
D'un autre côté, si vous regroupiez votre table Order
par CustomerID
, il n'aurait pas à effectuer plusieurs recherches de clé à chaque fois que vous interrogez la table pour CustomerId = ?
.
Le CLUSTERED INDEX
Devrait toujours être UNIQUE
, sinon SQL Server ajouterait une colonne INT invisible (= inutilisable) UNIQUIFIER
pour garantir l'unicité - et il serait beaucoup plus logique d'ajouter de vraies données (utilisables) puis quelques trucs aléatoires (selon l'ordre d'insertion).
Parce qu'un client passera (espérons-le) plusieurs commandes, nous devrons ajouter le OrderID
ou (si vous triez généralement pour cela) le OrderDate
(s'il s'agit d'une date/heure - sinon le client serait limité à une commande par jour) au CLUSTERED INDEX
et se retrouverait avec:
CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)
Les mêmes règles s'appliquent à la table OrderPositions
. Habituellement, la plupart des requêtes répertorient toutes les positions pour un ordre spécifique, vous devez donc créer le PK avec OrderPositionID
comme NONCLUSTERED
et un UNIQUE CLUSTERED INDEX
Sur OrderId, OrderPositionID
.
BTW: il est correct que la table Customer
soit groupée par son PK (la CustomerID
, car il s'agit d'une "table de niveau supérieur" et sera - dans une application typique - principalement interrogée par son identifiant client.
Tables de recherche pure comme par exemple Genders
ou InvoiceTypes
ou PaymentType
sont un autre exemple de tables qui doivent être regroupées par son PK (car vous les rejoindrez généralement sur GenderId
, InvoiceTypeId
ou PaymentTypeId
).
Lorsqu'un index clusterisé est jugé plus avantageux pour le système global qu'un PK clusterisé en utilisant une certaine mesure des performances. Il ne peut y avoir qu'un seul index cluster sur une table.
Des exemples de mesures des performances sont le temps de requête unique (vitesse), l'intégration des temps de requête totaux par rapport à la table (efficacité) et le fait d'avoir à ajouter de nombreuses colonnes d'inclusion à un à un très grand index non clusterisé afin d'obtenir des performances similaires à clusterisées (taille ).
Cela peut se produire lorsque les données sont généralement récupérées à l'aide d'un index qui n'est pas unique, contient des valeurs nulles (non autorisées dans un PK) ou lorsque le PK a été ajouté pour une raison secondaire (telle que la réplication ou l'identification des enregistrements de piste d'audit).