Estou construindo um aplicativo Web (sistema de gerenciamento de projetos) e fiquei pensando sobre isso quando se trata de desempenho.
Eu tenho uma tabela de problemas e dentro dela existem 12 chaves estrangeiras vinculadas a várias outras tabelas. desses, 8 deles eu precisaria me juntar para obter o campo de título das outras tabelas para que o registro fizesse sentido em um aplicativo da web, mas significa fazer 8 junções, o que parece realmente excessivo, especialmente porque eu estou apenas entrando 1 campo para cada uma dessas junções.
Agora também me disseram para usar uma chave primária de incremento automático (a menos que o sharding seja uma preocupação e, nesse caso, eu deveria usar um GUID) por motivos de permanência, mas quão ruim é usar um desempenho varchar (comprimento máximo 32)? Quero dizer, a maioria dessas tabelas provavelmente não terá muitos registros (a maioria deles deve ter menos de 20 anos). Além disso, se eu usar o título como chave primária, não precisarei fazer junções em 95% das vezes; portanto, para 95% do sql, ocorreria um impacto no desempenho (acho). A única desvantagem em que consigo pensar é que terei é maior uso de espaço em disco (mas em um dia é realmente um grande problema).
O motivo pelo qual eu uso tabelas de pesquisa para muitas dessas coisas, em vez de enumerações, é porque eu preciso que todos esses valores sejam configuráveis pelo usuário final através do próprio aplicativo.
Quais são as desvantagens de usar um varchar como chave primária para uma tabela que não tenha exceção de ter muitos registros?
UPDATE - Alguns testes
Então eu decidi fazer alguns testes básicos sobre essas coisas. Eu tenho 100000 registros e estas são as consultas base:
Consulta 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
Consulta Base FK INT
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
Também executei essas consultas com as seguintes adições:
- Selecione um item específico (onde i.key = 43298)
- Agrupar por i.id
- Ordenar por (it.title para int FK, i.issueTypeId para varchar FK)
- Limite (50000, 100)
- Agrupe e limite juntos
- Agrupe, encomende e limite juntos
Os resultados para estes onde:
TIPO DE CONSULTA: VARCHAR FK TIME / INT FK TIME
Consulta base: ~ 4ms / ~ 52ms
Selecione um item específico: ~ 140ms / ~ 250ms
Agrupar por i.id: ~ 4ms / ~ 2.8sec
Ordenar por: ~ 231ms / ~ 2seg
Limite: ~ 67ms / ~ 343ms
Agrupe e limite juntos: ~ 504ms / ~ 2seg
Agrupe, encomende e limite juntos: ~ 504ms / ~2.3seg
Agora eu não sei qual configuração eu poderia fazer para tornar um ou outro (ou ambos) mais rápido, mas parece que o VARCHAR FK vê mais rapidamente nas consultas de dados (às vezes muito mais rápido).
Acho que tenho que escolher se essa melhoria de velocidade vale o tamanho extra de dados / índice.