Je construis une application web (système de gestion de projet) et je me pose des questions à ce sujet en termes de performances.
J'ai une table Issues et à l'intérieur il y a 12 clés étrangères reliant à diverses autres tables. de ceux-ci, 8 d'entre eux, je devrais rejoindre pour obtenir le champ de titre des autres tables afin que l'enregistrement ait un sens dans une application Web, mais cela signifie ensuite faire 8 jointures, ce qui semble vraiment excessif, d'autant plus que je ne fais que tirer 1 champ pour chacune de ces jointures.
Maintenant, on m'a également dit d'utiliser une clé primaire à incrémentation automatique (sauf si le partage est un problème auquel cas je devrais utiliser un GUID) pour des raisons de permanence, mais à quel point est-il mauvais d'utiliser une varchar (longueur maximale 32) en termes de performances? Je veux dire que la plupart de ces tableaux n'auront probablement pas de nombreux enregistrements (la plupart d'entre eux devraient avoir moins de 20 ans). De plus, si j'utilise le titre comme clé primaire, je n'aurai pas à faire de jointures 95% du temps, donc pour 95% du sql, j'aurais même un impact sur les performances (je pense). Le seul inconvénient auquel je peux penser, c'est que j'aurai une utilisation d'espace disque plus élevée (mais un jour, c'est vraiment un gros problème).
La raison pour laquelle j'utilise des tables de recherche pour beaucoup de ces choses au lieu des énumérations est parce que j'ai besoin que toutes ces valeurs soient configurables par l'utilisateur final via l'application elle-même.
Quels sont les inconvénients de l'utilisation d'un varchar comme clé primaire pour une table qui n'est pas exempte d'avoir de nombreux enregistrements?
MISE À JOUR - Quelques tests
J'ai donc décidé de faire des tests de base sur ce genre de choses. J'ai 100 000 enregistrements et ce sont les requêtes de base:
Base VARCHAR FK Query
SELECT i.id, i.key, i.title, i.reporterUserUsername, i.assignedUserUsername, i.projectTitle,
i.ProjectComponentTitle, i.affectedProjectVersionTitle, i.originalFixedProjectVersionTitle,
i.fixedProjectVersionTitle, i.durationEstimate, i.storyPoints, i.dueDate,
i.issueSecurityLevelId, i.creatorUserUsername, i.createdTimestamp,
i.updatedTimestamp, i.issueTypeId, i.issueStatusId
FROM ProjectManagement.Issues i
Base INT FK Query
SELECT i.id, i.key, i.title, ru.username as reporterUserUsername,
au.username as assignedUserUsername, p.title as projectTitle,
pc.title as ProjectComponentTitle, pva.title as affectedProjectVersionTitle,
pvo.title as originalFixedProjectVersionTitle, pvf.title as fixedProjectVersionTitle,
i.durationEstimate, i.storyPoints, i.dueDate, isl.title as issueSecurityLevelId,
cu.username as creatorUserUsername, i.createdTimestamp, i.updatedTimestamp,
it.title as issueTypeId, is.title as issueStatusId
FROM ProjectManagement2.Issues i
INNER JOIN ProjectManagement2.IssueTypes `it` ON it.id = i.issueTypeId
INNER JOIN ProjectManagement2.IssueStatuses `is` ON is.id = i.issueStatusId
INNER JOIN ProjectManagement2.Users `ru` ON ru.id = i.reporterUserId
INNER JOIN ProjectManagement2.Users `au` ON au.id = i.assignedUserId
INNER JOIN ProjectManagement2.Users `cu` ON cu.id = i.creatorUserId
INNER JOIN ProjectManagement2.Projects `p` ON p.id = i.projectId
INNER JOIN ProjectManagement2.`ProjectComponents` `pc` ON pc.id = i.projectComponentId
INNER JOIN ProjectManagement2.ProjectVersions `pva` ON pva.id = i.affectedProjectVersionId
INNER JOIN ProjectManagement2.ProjectVersions `pvo` ON pvo.id = i.originalFixedProjectVersionId
INNER JOIN ProjectManagement2.ProjectVersions `pvf` ON pvf.id = i.fixedProjectVersionId
INNER JOIN ProjectManagement2.IssueSecurityLevels isl ON isl.id = i.issueSecurityLevelId
J'ai également exécuté ces requêtes avec les ajouts suivants:
- Sélectionnez un élément spécifique (où i.key = 43298)
- Grouper par i.id
- Trier par (it.title pour int FK, i.issueTypeId pour varchar FK)
- Limite (50000, 100)
- Regrouper et limiter ensemble
- Grouper, ordonner et limiter ensemble
Les résultats pour ceux-ci où:
TYPE DE REQUÊTE: VARCHAR FK TIME / INT FK TIME
Requête de base: ~ 4 ms / ~ 52 ms
Sélectionnez un élément spécifique: ~ 140 ms / ~ 250 ms
Grouper par i.id: ~ 4ms / ~ 2.8sec
Trier par: ~ 231ms / ~ 2sec
Limite: ~ 67 ms / ~ 343 ms
Grouper et limiter ensemble: ~ 504 ms / ~ 2 s
Regroupez, commandez et limitez ensemble: ~ 504 ms / ~ 2,3 s
Maintenant, je ne sais pas quelle configuration je pourrais faire pour rendre l'un ou l'autre (ou les deux) plus rapide, mais il semble que le VARCHAR FK voit plus rapidement dans les requêtes de données (parfois beaucoup plus rapide).
Je suppose que je dois choisir si cette amélioration de la vitesse vaut la taille supplémentaire des données / index.