Estoy creando una aplicación web (sistema de gestión de proyectos) y me he estado preguntando sobre esto en lo que respecta al rendimiento.
Tengo una tabla de problemas y en su interior hay 12 claves externas que se vinculan a otras tablas. De ellos, 8 de ellos tendrían que unirme para obtener el campo de título de las otras tablas para que el registro tenga sentido en una aplicación web, pero luego significa hacer 8 uniones, lo que parece realmente excesivo, especialmente porque solo estoy llegando 1 campo para cada una de esas uniones.
Ahora también me han dicho que use una clave primaria de incremento automático (a menos que la división sea una preocupación, en cuyo caso debería usar un GUID) por razones de permanencia, pero ¿qué tan malo es usar un rendimiento varchar (longitud máxima 32)? Quiero decir que la mayoría de estas tablas probablemente no tendrán muchos registros (la mayoría de ellos deberían ser menores de 20). Además, si uso el título como la clave principal, no tendré que unirme el 95% del tiempo, por lo que para el 95% del sql, incluso se produciría cualquier golpe de rendimiento (creo). El único inconveniente que se me ocurre es que tendré un mayor uso de espacio en disco (pero un día es realmente un gran problema).
La razón por la que uso tablas de búsqueda para muchas de estas cosas en lugar de enumeraciones es porque necesito que todos estos valores sean configurables por el usuario final a través de la aplicación misma.
¿Cuáles son las desventajas de usar un varchar como clave principal para una tabla que no tiene la excepción de tener muchos registros?
ACTUALIZACIÓN - Algunas pruebas
Así que decidí hacer algunas pruebas básicas sobre estas cosas. Tengo 100000 registros y estas son las consultas básicas:
Consulta básica de 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
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
También ejecuté estas consultas con las siguientes adiciones:
- Seleccione un elemento específico (donde i.key = 43298)
- Agrupar por i.id
- Ordenar por (it.title para int FK, i.issueTypeId para varchar FK)
- Límite (50000, 100)
- Agrupar y limitar juntos
- Agrupar, ordenar y limitar juntos
Los resultados para estos donde:
TIPO DE CONSULTA: VARCHAR FK TIME / INT FK TIME
Consulta base: ~ 4ms / ~ 52ms
Seleccione un elemento específico: ~ 140ms / ~ 250ms
Agrupar por i.id: ~ 4ms / ~ 2.8sec
Ordenar por: ~ 231 ms / ~ 2 segundos
Límite: ~ 67ms / ~ 343ms
Agrupar y limitar juntos: ~ 504 ms / ~ 2 segundos
Agrupar, ordenar y limitar juntos: ~ 504ms /~2.3sec
Ahora no sé qué configuración podría hacer para que uno u otro (o ambos) sean más rápidos, pero parece que el VARCHAR FK ve más rápido en las consultas de datos (a veces mucho más rápido).
Supongo que tengo que elegir si esa mejora de la velocidad vale el tamaño extra de datos / índice.