J'ai un Competitions
tableau de résultats qui contient les noms des membres de l'équipe et leur classement d'une part.
D'autre part, je dois maintenir un tableau des noms de concurrents uniques :
CREATE TABLE Competitors (cName nvarchar(64) primary key)
Maintenant, j'ai environ 200000 résultats dans la 1ère table et lorsque la table des concurrents est vide, je peux effectuer ceci:
INSERT INTO Competitors SELECT DISTINCT Name FROM CompResults
Et la requête ne prend que 5 secondes pour insérer environ 11 000 noms.
Jusqu'à présent, ce n'est pas une application critique, donc je peux envisager de tronquer le tableau des concurrents une fois par mois, lorsque je reçois les nouveaux résultats du concours avec environ 10 000 lignes.
Mais quelle est la meilleure pratique lorsque de nouveaux résultats sont ajoutés, avec des concurrents nouveaux ET existants? Je ne veux pas tronquer la table des concurrents existante
Je dois effectuer l'instruction INSERT pour les nouveaux concurrents uniquement et ne rien faire s'ils existent.
la source
NVARCHAR(64)
colonne votre clé primaire (et donc: clustering) !! Tout d'abord - c'est une clé très large - jusqu'à 128 octets; et deuxièmement, sa taille est variable - encore une fois: pas optimale ... C'est à peu près le pire choix que vous puissiez avoir - vos performances seront d'enfer, et la fragmentation des tables et des index sera à 99,9% tout le temps .....cName
échec dans trois des quatre catégories ... (ce n'est pas étroit, ce n'est probablement pas statique, et ce n'est certainement pas en augmentation constante)Réponses:
Sémantiquement, vous demandez "insérer des concurrents là où n'existe pas déjà":
la source
Une autre option est de quitter votre table de résultats avec votre table de concurrents existante et de trouver les nouveaux concurrents en filtrant les enregistrements distincts qui ne correspondent pas à la jointure:
La nouvelle syntaxe MERGE offre également un moyen compact, élégant et efficace de le faire:
la source
Je ne sais pas pourquoi quelqu'un d'autre n'a pas encore dit cela;
NORMALISER.
Vous avez une table qui modélise les compétitions? Les compétitions sont constituées de concurrents? Vous avez besoin d'une liste distincte de concurrents dans une ou plusieurs compétitions ......
Vous devriez avoir les tableaux suivants .....
Avec des contraintes sur CompetitionCompetitors.CompetitionID et CompetitorID pointant vers les autres tables.
Avec ce type de structure de table - vos clés sont toutes de simples INTS - il ne semble pas y avoir de bonne CLE NATURELLE qui conviendrait au modèle, donc je pense qu'une CLÉ SURROGATE convient bien ici.
Donc, si vous aviez ceci, pour obtenir la liste distincte des concurrents dans un concours particulier, vous pouvez émettre une requête comme celle-ci:
Et si vous vouliez le score de chaque compétition à laquelle participe un concurrent:
Et lorsque vous avez un nouveau concours avec de nouveaux concurrents, il vous suffit de vérifier ceux qui existent déjà dans le tableau des concurrents. S'ils existent déjà, vous n'insérez pas dans Competitor pour ces concurrents et insérez pour les nouveaux.
Ensuite, vous insérez le nouveau Concours en Compétition et enfin il vous suffit de faire tous les liens dans CompetitionCompetitors.
la source
Vous devrez rejoindre les tables ensemble et obtenir une liste de concurrents uniques qui n'existent pas déjà
Competitors
.Cela insérera des enregistrements uniques.
Il peut arriver un moment où cette insertion doit être faite rapidement sans pouvoir attendre la sélection de noms uniques. Dans ce cas, vous pouvez insérer les noms uniques dans une table temporaire, puis utiliser cette table temporaire pour l'insérer dans votre table réelle. Cela fonctionne bien car tout le traitement se produit au moment où vous insérez dans une table temporaire, donc cela n'affecte pas votre table réelle. Ensuite, lorsque vous avez terminé le traitement, vous effectuez une insertion rapide dans la table réelle. Je pourrais même envelopper la dernière partie, où vous insérez dans la vraie table, à l'intérieur d'une transaction.
la source
Les réponses ci-dessus qui parlent de normalisation sont excellentes! Mais que faire si vous vous trouvez dans une position comme moi où vous n'êtes pas autorisé à toucher le schéma ou la structure de la base de données en l'état? Par exemple, les DBA sont des «dieux» et toutes les révisions suggérées vont dans / dev / null?
À cet égard, je pense que cela a également été répondu avec cette publication de Stack Overflow en ce qui concerne tous les utilisateurs ci-dessus donnant des échantillons de code.
Je republie le code de INSERT VALUES WHERE NOT EXISTS, ce qui m'a le plus aidé car je ne peux pas modifier les tables de base de données sous-jacentes:
Le code ci-dessus utilise des champs différents de ceux que vous avez, mais vous obtenez l'essentiel des différentes techniques.
Notez que selon la réponse originale sur Stack Overflow, ce code a été copié à partir d'ici .
Quoi qu'il en soit, mon argument est que les «meilleures pratiques» se résument souvent à ce que vous pouvez et ne pouvez pas faire aussi bien que la théorie.
Bonne chance!
la source
La normalisation de vos tables opérationnelles comme suggéré par Transact Charlie est une bonne idée et vous évitera de nombreux maux de tête et problèmes au fil du temps - mais il existe des éléments tels que les tables d' interface , qui prennent en charge l'intégration avec des systèmes externes, et les tableaux de rapport , qui prennent en charge des choses comme l'analyse En traitement; et ces types de tableaux ne doivent pas nécessairement être normalisés - en fait, très souvent, il est beaucoup, beaucoup plus pratique et performant pour eux de ne pas être .
Dans ce cas, je pense que la proposition de Transact Charlie pour vos tables opérationnelles est bonne.
Mais j'ajouterais un index (pas nécessairement unique) à CompetitorName dans la table Competitors pour prendre en charge des jointures efficaces sur CompetitorName à des fins d'intégration (chargement de données à partir de sources externes), et je mettrais une table d'interface dans le mélange: CompetitionResults.
Les résultats de la compétition doivent contenir toutes les données de vos résultats de compétition. Le but d'une table d'interface comme celle-ci est de rendre aussi rapide et facile que possible la tronquer et la recharger à partir d'une feuille Excel ou d'un fichier CSV, ou quelle que soit la forme dans laquelle vous avez ces données.
Cette table d'interface ne doit pas être considérée comme faisant partie de l'ensemble normalisé de tables opérationnelles.Ensuite, vous pouvez vous joindre à CompetitionResults comme suggéré par Richard, pour insérer des enregistrements dans des concurrents qui n'existent pas déjà, et mettre à jour ceux qui existent (par exemple si vous avez réellement plus d'informations sur les concurrents, comme leur numéro de téléphone ou leur adresse e-mail).
Une chose que je voudrais noter - en réalité, il me semble que le nom du concurrent est très peu susceptible d'être unique dans vos données . Dans 200 000 concurrents, vous pouvez très bien avoir 2 David Smith ou plus, par exemple. Je vous recommande donc de collecter plus d'informations auprès des concurrents, telles que leur numéro de téléphone ou une adresse e-mail, ou quelque chose qui est plus susceptible d'être unique.
Votre table opérationnelle, Concurrents, doit avoir une seule colonne pour chaque élément de données qui contribue à une clé naturelle composite; par exemple, il doit avoir une colonne pour une adresse e-mail principale. Mais la table d'interface doit avoir un emplacement pour l' ancien et le nouveau valeurs pour une adresse e-mail principale, afin que l'ancienne valeur puisse être utilisée pour rechercher l'enregistrement dans Concurrents et mettre à jour cette partie avec la nouvelle valeur.
Donc CompetitionResults devrait avoir quelques champs "anciens" et "nouveaux" - oldEmail, newEmail, oldPhone, newPhone, etc. De cette façon, vous pouvez former une clé composite, dans Competitors, à partir de CompetitorName, Email et Phone.
Ensuite, lorsque vous avez des résultats de compétition, vous pouvez tronquer et recharger votre table CompetitionResults à partir de votre feuille Excel ou de tout ce que vous avez, et exécuter une seule insertion efficace pour insérer tous les nouveaux concurrents dans la table des concurrents, et une mise à jour unique et efficace pour mettre à jour toutes les informations sur les concurrents existants à partir des résultats du concours. Et vous pouvez faire une seule insertion pour insérer de nouvelles lignes dans le tableau CompetitionCompetitors. Ces opérations peuvent être effectuées dans une procédure stockée ProcessCompetitionResults, qui pourrait être exécutée après le chargement de la table CompetitionResults.
C'est une sorte de description rudimentaire de ce que j'ai vu faire à maintes reprises dans le monde réel avec Oracle Applications, SAP, PeopleSoft et une longue liste d'autres suites logicielles d'entreprise.
Un dernier commentaire que je ferais est celui que j'ai déjà fait sur SO: Si vous créez une clé étrangère qui garantit qu'un concurrent existe dans la table des concurrents avant de pouvoir ajouter une ligne avec ce concurrent à CompetitionCompetitors, assurez-vous que la clé étrangère est définie pour mettre en cascade les mises à jour et les suppressions . De cette façon, si vous devez supprimer un concurrent, vous pouvez le faire et toutes les lignes associées à ce concurrent seront automatiquement supprimées. Sinon, par défaut, la clé étrangère vous demandera de supprimer toutes les lignes associées de CompetitionCompetitors avant de vous permettre de supprimer un concurrent.
(Certaines personnes pensent que les clés étrangères non en cascade sont une bonne précaution de sécurité, mais mon expérience est qu'elles sont juste une douleur effrayante dans les fesses qui sont le plus souvent simplement le résultat d'un oubli et qu'elles créent un tas de travail pour les administrateurs de base de données. Le fait que des personnes suppriment accidentellement des éléments est la raison pour laquelle vous avez des boîtes de dialogue "êtes-vous sûr" et divers types de sauvegardes régulières et de sources de données redondantes. Il est beaucoup plus courant de vouloir supprimer un concurrent, dont les données sont toutes foiré par exemple, c'est d'en supprimer accidentellement un puis de dire "Oh non! Je ne voulais pas faire ça! Et maintenant je n'ai pas leurs résultats de compétition! Aaaahh!" Ce dernier est certainement assez courant, donc , vous devez y être préparé, mais le premier est beaucoup plus courant,Donc, le moyen le plus simple et le meilleur de se préparer à l'ancien, imo, est simplement de faire en sorte que les clés étrangères mettent en cascade les mises à jour et les suppressions.)
la source
Ok, cela a été demandé il y a 7 ans, mais je pense que la meilleure solution ici est de renoncer complètement à la nouvelle table et de le faire simplement comme une vue personnalisée. De cette façon, vous ne dupliquez pas de données, vous ne vous inquiétez pas des données uniques et cela ne touche pas la structure réelle de la base de données. Quelque chose comme ça:
D'autres éléments peuvent être ajoutés ici comme des jointures sur d'autres tables, des clauses WHERE, etc. C'est probablement la solution la plus élégante à ce problème, car vous pouvez maintenant simplement interroger la vue:
... et ajoutez les clauses WHERE, IN ou EXISTS à la requête de vue.
la source