Sto costruendo un'applicazione web (sistema di gestione del progetto) e mi sono chiesto a questo riguardo alle prestazioni.
Ho una tabella dei problemi e al suo interno ci sono 12 chiavi esterne che si collegano a varie altre tabelle. di questi, 8 di cui avrei bisogno di unirmi per ottenere il campo del titolo dagli altri tavoli in modo che il record abbia un senso in un'applicazione web, ma significa quindi fare 8 join che sembrano davvero eccessivi soprattutto perché sto solo inserendo 1 campo per ciascuno di quei join.
Ora mi è stato anche detto di usare una chiave primaria ad incremento automatico (a meno che lo sharding non sia un problema, nel qual caso dovrei usare un GUID) per motivi di permanenza, ma quanto è male usare un varchar (lunghezza massima 32) dal punto di vista delle prestazioni? Voglio dire, la maggior parte di queste tabelle probabilmente non avrà molti record (la maggior parte dovrebbe avere meno di 20 anni). Inoltre, se uso il titolo come chiave primaria, non dovrò più unirmi al 95% delle volte, quindi per il 95% del sql, mi verificherei anche qualsiasi hit di prestazione (penso). L'unico aspetto negativo che mi viene in mente è che ho è che avrò un maggiore utilizzo dello spazio su disco (ma un giorno è davvero un grosso problema).
Il motivo per cui utilizzo tabelle di ricerca per molte cose invece di enum è perché ho bisogno che tutti questi valori siano configurabili dall'utente finale attraverso l'applicazione stessa.
Quali sono gli svantaggi dell'utilizzo di varchar come chiave primaria per una tabella a cui non viene escluso di avere molti record?
AGGIORNAMENTO - Alcuni test
Quindi ho deciso di fare alcuni test di base su queste cose. Ho 100000 record e queste sono le query di base:
Query di base VARCHAR FK
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
Query FK INT di base
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
Ho anche eseguito queste query con le seguenti aggiunte:
- Seleziona un articolo specifico (dove i.key = 43298)
- Raggruppa per i.id
- Ordina per (it.title per int FK, i.issueTypeId per varchar FK)
- Limite (50000, 100)
- Raggruppa e limita insieme
- Raggruppa, ordina e limita insieme
I risultati per questi dove:
TIPO DI QUERY: VARCHAR FK TIME / INT FK TIME
Query di base: ~ 4ms / ~ 52ms
Seleziona un articolo specifico: ~ 140ms / ~ 250ms
Raggruppa per i.id: ~ 4ms / ~ 2.8sec
Ordina per: ~ 231ms / ~ 2sec
Limite: ~ 67ms / ~ 343ms
Raggruppa e limita insieme: ~ 504ms / ~ 2sec
Raggruppa, ordina e limita insieme: ~ 504ms /~2.3sec
Ora non so quale configurazione potrei fare per rendere l'uno o l'altro (o entrambi) più veloci, ma sembra che VARCHAR FK veda più velocemente nelle query per i dati (a volte molto più velocemente).
Immagino di dover scegliere se quel miglioramento di velocità valga la dimensione extra di dati / indice.