Tenho duas tabelas, para simplificar vamos chamá-las employees
de e employee_comms
:
employee
:
eu ia | nome | departamento |
---|---|---|
1 | Jane | Manutenção |
2 | João | Projeto |
employee_comms
:
eu ia | ID do contato | tipo_de_comunicação | valor_de_comunicação |
---|---|---|---|
1 | 1 | [email protegido] | |
2 | 1 | telefone | 555 324 6573 |
3 | 2 | [email protegido] | |
4 | 2 | telefone | 555 201 5843 |
Atualmente, comms_type
só pode ser phone
ou email
.
Escrevi uma consulta para filtrar funcionários por departamento e mostrar e-mail e telefone de cada um:
SELECT
d.id,
d.name,
d.dept,
p.comms_value as phone,
e.comms_value as email
FROM
(
SELECT *
FROM employee
WHERE dept = 'Design'
) AS d
LEFT JOIN (
SELECT contact_id, comms_value
FROM employee_comms
WHERE comms_type = 'phone'
) AS p ON (d.id = p.contact_id)
LEFT JOIN (
SELECT contact_id, comms_value
FROM employee_comms
WHERE comms_type = 'email'
) AS e ON (d.id = e.contact_id);
O resultado é uma tabela onde a segunda tabela é transposta com linhas únicas e exclusivas onde nenhum employee
valor é duplicado ( id
, name
):
eu ia | nome | departamento | telefone | |
---|---|---|---|---|
2 | João | Projeto | [email protegido] | 555 201 5843 |
Atualmente, ele resolve minhas necessidades, mas continuo pensando que deveria haver uma solução mais eficiente, já que estou consultando a employee_comms
tabela duas vezes e isso pode se tornar um problema de desempenho quando a employee_comms
tabela ficar grande (e isso vai acontecer).
P: Existe uma abordagem mais eficiente?
Você poderia fazer algo assim (todo o código abaixo está disponível no fiddle aqui ):
Resultado (adicionei alguns outros dados aos seus):
Confira os
ANALYZE (EXPLAIN...
trechos que incluí nos meus violinos.Há uma série de problemas com seu esquema.
Você está usando o ( temido ) modelo EAV (Entity Attribute Value) - isso é (geralmente - > 99,99...%) um
bad idea™
! Veja aqui o que tem a dizer sobre isso - também aqui (e links dentro). Você está misturando números de telefone e e-mails no mesmo campo - em vez de misturá-los na mesma tabela - o que é bom.No entanto, você tem mais de um tipo de comunicação por pessoa - então o que você precisa é de uma
associative entity
(também conhecida como tabela de junção (há > 15 outros nomes na página Wiki).OU você pode ter uma tabela separada para cada tipo de comunicação - ou seja, para telefone(s), e-mail(s)... essa também é uma abordagem válida - se não houver centenas desses tipos.
Então, pegando a segunda ideia primeiro, criei uma
email
tabela (e umaphone
tabela - não mostrada, veja o violino aqui ) como segue:Agora, observe que eu posso implementar
CHECK CONSTRAINT
s - estes são umgood thing™
! Seu banco de dados é seu último bastião de defesa contra dados ruins, então usar uma regex para verificar novamente se você não tem números de telefone ou e-mails inválidos deve (pelo menos ajudar a) manter seus dados válidos!Então, você terá consultas como esta:
Resultado:
Você pode adicionar mais tabelas conforme aqui - adicionei um
priority
campo se você quiser usar a 1ª prioridade do usuário como método de contato preferencial.Você tem então:
Resultado:
Basicamente, você pode obter muito mais informações muito mais rápida e facilmente ao não usar o paradigma EAV ( antipadrão ) e seus stakeholders/clientes também ficarão mais felizes! Um EAV tem complexidade ON^2 (ou ON!) - conforme você adiciona mais registros às suas tabelas EAV, suas consultas rapidamente se tornarão monstros incontroláveis - enquanto que se você distinguir claramente suas entidades, sua vida e suas consultas serão muito mais fáceis!