Je développe une base de données SQL Server 2012 et j'ai un doute sur les colonnes nvarchar comme clés primaires.
J'ai ce tableau:
CREATE TABLE [dbo].[CODES]
(
[ID_CODE] [bigint] IDENTITY(1,1) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
[CODE] [nvarchar](20) NOT NULL,
[FLAG] [tinyint] NOT NULL,
[IS_TRANSMITTED] [bit] NOT NULL DEFAULT 0,
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE_LEVEL] ASC,
[CODE] ASC
)
)
Mais maintenant, je veux utiliser la [CODE]
colonne comme clé primaire et supprimer la [ID_CODE]
colonne.
Y a-t-il un problème ou une pénalité si j'ai une NVARCHAR
colonne en tant que PRIMARY KEY
?
[CODE]
la valeur de la colonne doit être unique, j'ai donc pensé pouvoir définir une UNIQUE
contrainte sur cette colonne.
Dois-je utiliser [CODE]
comme clé primaire ou il est préférable de définir une UNIQUE
contrainte sur la [CODE]
colonne?
sql-server
primary-key
unique-constraint
VansFannel
la source
la source
CODE
colonne doit être unique, mais pas une clé primaire. Je soupçonne qu'il contient des informations. Si ces informationsCODE
peuvent être modifiées de quelque manière que ce soit, alors votre information devrait changer ou être périmée. Cela rendrait votre clé primaire volatile, et je ne vois pas bien cela se terminer. Il vaut mieux laisser votre PK être une clé et votre CODE peut faire ce qu'il veut. Juste une opinion.Réponses:
Oui, il y a absolument des conséquences négatives à utiliser une chaîne au lieu d'un type numérique pour une clé primaire, et plus encore si ce PK est en cluster (ce qui est effectivement le cas dans votre cas). Cependant, la mesure dans laquelle vous voyez les effets de l'utilisation d'un champ de chaîne est fonction de a) du nombre de lignes de cette table et b) du nombre de lignes des autres tables qui sont à clé étrangère pour ce PK. Si vous n'avez que 10 000 lignes dans cette table et 100 000 lignes dans quelques autres tables qui FK vers cette table via ce champ, alors ce ne sera peut-être pas si visible. Mais ces effets deviennent certainement plus visibles à mesure que le nombre de lignes augmente.
Vous devez tenir compte du fait que les champs d'un index cluster sont reportés sur les index non cluster. Donc, vous ne regardez pas seulement jusqu'à 40 octets par ligne, mais (40 * un_nombre) octets. Et dans toutes les tables FK, vous avez ces mêmes 40 octets dans la ligne, plus souvent qu'autrement, il y aura un index non clusterisé sur ce champ car il est utilisé dans JOINs, donc maintenant il est vraiment doublé dans toutes les tables que FK à celui-là. Si l'on est enclin à penser que 40 octets * 1 million de lignes * 10 copies ne sont rien à craindre, veuillez consulter mon article Disk Is Cheap! ORLY? qui détaille tous (ou au moins la plupart) des domaines touchés par cette décision.
L'autre chose à considérer est que le filtrage et le tri sur les chaînes, en particulier lorsque vous n'utilisez pas un classement binaire (je suppose que vous utilisez la base de données par défaut qui est généralement insensible à la casse) est beaucoup moins efficace (c'est-à-dire prend plus de temps) que lorsque vous utilisez
INT
/BIGINT
. Cela a un impact sur toutes les requêtes qui filtrent / joignent / trient sur ce champ.Par conséquent, utiliser quelque chose comme
CHAR(5)
serait probablement OK pour un PK en cluster, mais surtout s'il était également défini avecCOLLATE Latin1_General_100_BIN2
(ou quelque chose comme ça).Et la valeur de
[CODE]
jamais peut-elle changer? Si oui, c'est encore plus de raison de ne pas l'utiliser comme PK (même si vous définissez les FK surON UPDATE CASCADE
). Si cela ne peut pas ou ne changera jamais, c'est bien, mais il y a encore plus de raisons de ne pas l'utiliser comme PK en cluster.Bien sûr, la question peut être mal formulée car il semble que vous ayez déjà ce champ dans votre PK.
Quoi qu'il en soit, votre meilleure option, de loin, est d'utiliser
[ID_CODE]
comme Clustered PK, d'utiliser ce champ dans les tables connexes comme FK et de le conserver[CODE]
commeUNIQUE INDEX
(ce qui signifie qu'il s'agit d'une "clé alternative").Mise à jour
Un peu plus d'informations basées sur cette question dans un commentaire sur cette réponse:
Tout cela dépend d'un grand nombre de facteurs, dont certains que j'ai déjà mentionnés mais qui seront reformulés:
Une clé primaire est la façon dont la ligne individuelle est identifiée, qu'elle soit référencée ou non par des clés étrangères. La façon dont votre système identifie la ligne en interne est liée, mais pas nécessairement la même que, à la façon dont vos utilisateurs s'identifient / cette ligne. Toute colonne NOT NULL avec des données uniques pourrait fonctionner, mais il y a des problèmes pratiques à prendre en compte, surtout si le PK est, en fait, référencé par des FK. Par exemple, les GUID sont uniques et certaines personnes aiment vraiment les utiliser pour diverses raisons, mais elles sont assez mauvaises pour les index clusterisés (
NEWSEQUENTIALID
c'est mieux, mais pas parfait). D'un autre côté, les GUID sont très bien comme clés alternatives et utilisés par l'application pour rechercher la ligne, mais les JOIN se font toujours à l'aide d'un PK INT (ou similaire).Jusqu'à présent, vous ne nous avez pas dit comment le
[CODE]
champ s'intègre dans le système sous tous les angles, en dehors de mentionner maintenant que c'est ainsi que vous recherchez les lignes, mais est-ce pour toutes les requêtes ou juste pour certaines? Par conséquent:Concernant la
[CODE]
valeur:Concernant ce tableau:
[CODE]
ou[ID_CODE]
) sont-ils utilisés dans d'autres tables, même s'ils ne sont pas explicitement à clé étrangère?[CODE]
le seul champ est utilisé pour obtenir des lignes individuelles, à quoi sert le[ID_CODE]
champ? S'il n'est pas utilisé, pourquoi l'avoir en premier lieu (ce qui pourrait dépendre de la réponse "Le[CODE]
champ peut-il jamais changer?")?Cette décision ne peut pas être prise uniquement sur la question "NVARCHAR oui ou non?". Je dirai encore que, d'une manière générale, je ne trouve pas que ce soit une bonne idée, mais il y a certainement des moments où c'est bien. Étant donné le peu de champs dans ce tableau, il est peu probable qu'il y ait plus, ou du moins pas beaucoup, d'index. Donc, vous pourriez être d'accord dans les deux cas
[CODE]
comme index clusterisé. Et si aucune autre table ne fait référence à cette table, vous pouvez également en faire le PK. Mais, si d'autres tables font référence à cette table, j'opterais pour le[ID_CODE]
champ comme PK, même s'il n'est pas en cluster.la source
[ID_CODE]
, asPRIMARY KEY
, la meilleure option si j'utilise la[CODE]
colonne pour rechercher la table?Vous devez séparer les concepts:
La clé primaire est un concept de conception , une propriété logique des entrées du tableau. Elle doit être immuable pendant la durée de vie de l'entrée de table et doit être la clé utilisée dans l'application pour référencer l'entrée.
L'index cluster est un concept de stockage , une propriété physique. Il doit être le chemin d'accès le plus courant pour les requêtes, il doit servir à satisfaire comme index de couverture pour la plupart des cas et à satisfaire autant de requêtes de plage que possible.
N'est pas requis pour que la clé primaire soit l'index cluster. Vous pouvez avoir
ID_CODE
comme(CODE_LEVEL, CODE)
clé PK et comme clé en cluster. Ou l'inverse.Une clé en cluster plus grande a des répercussions négatives, car la clé plus large signifie une densité plus faible sur les pages d'index et une plus grande taille consommée sur tous les index non cluster. il y a déjà eu des tonnes d'encre renversées sur ce sujet, par exemple. Partir de Plus de considérations sur la clé de clustering - le débat sur l'index clusterisé continue! .
Mais l'essentiel est que le choix de la clé d'index cluster est principalement un compromis. D'une part, vous avez des exigences de taille de stockage, avec des répercussions générales sur les performances (clé plus grande -> taille plus grande -> plus d'E / S et la bande passante d'E / S est probablement la ressource la plus rare dont vous disposez). D'un autre côté, le choix de la mauvaise clé en cluster au nom des économies d'espace peut avoir des conséquences sur les performances des requêtes, souvent pires que les problèmes résultant d'une clé large.
Quant au choix de la clé primaire, il ne devrait même pas être un problème: votre modèle de données, la logique de votre application, doivent dicter ce qu'est la clé primaire.
Cela étant dit, mon 2c:
NVARCHAR(20)
n'est pas large. Est une taille de clé en cluster parfaitement acceptable, même pour une grande table.la source
[ID_CODE]
, asPRIMARY KEY
, la meilleure option si j'utilise la[CODE]
colonne (et peut-être[CODE_LEVEL]
) pour rechercher la table?[CODE]
colonne comme CLÉ PRIMAIRE.Je n'autoriserais jamais personne à créer
nvarchar(20)
un PK dans ma base de données. Vous gaspillez de l'espace disque et de la mémoire cache. Chaque index de cette table et tous les FK qui y sont répliquent cette valeur large. Peut-être un char (20) s'ils peuvent le justifier. Dans quel type de données essayez-vous de stockerCODE
? Avez-vous vraiment besoin de stocker des caractères nvarchar? J'ai tendance à rendre les valeurs «internes» des PK non vues par les utilisateurs, et j'essaie de garder les valeurs affichées séparément. Les valeurs affichées doivent parfois être modifiées, ce qui devient très problématique avec les PK + FK.Vous rendez-vous également compte qu'une «identité bigint (1,1)» peut augmenter jusqu'à 9 223 372 036 854 775 807?
À moins que vous ne construisiez cette base de données pour Google, une normale
int identity (1,1)
avec sa limite de plus de 2 milliards ne suffira-t-elle pas?la source
[ID_CODE]
, asPRIMARY KEY
, la meilleure option si j'utilise la[CODE]
colonne pour rechercher la table? Merci.Il ne devrait y avoir aucune pénalité inhérente / perceptible autre que vous risquez d'utiliser des touches larges lorsque vous utilisez nvarchar / varchar si vous ne le savez pas. Surtout si vous commencez à les combiner dans des clés composites.
Mais dans votre exemple d'une longueur (20), vous devriez être bien et je ne m'inquiéterais pas beaucoup à ce sujet. Parce que si CODE est la façon dont vous interrogez principalement vos données - un index clusterisé qui semble très sensé.
Cependant, vous devez déterminer si vous le souhaitez réellement comme clé primaire ou simplement comme index unique (en cluster). Il y a une (petite) différence entre l'index clusterisé et la clé primaire (fondamentalement - la clé primaire identifie vos données, mais l'index est la façon dont vous interrogez les données), donc si vous le souhaitez, vous pouvez tout aussi facilement créer votre ID_Code comme clé primaire et créer un index cluster unique sur CODE. (remarque: SQL Server transformera automatiquement votre clé primaire en index cluster, sauf si vous avez créé manuellement l'index cluster vous-même)
Vérifiez également si vous avez réellement besoin d'ID_Code, vous disposez maintenant d'un CODE unique.
la source
NVARCHAR(20)
est de 40 octets (max), et comme il s'agit d' une colonne de longueur variable , ce n'est pas vraiment le meilleur choix pour un index clusterisé.ID_CODE
être unBIGINT IDENTITY
serait le bien meilleur choix ici!