Eu tenho uma pergunta sobre a melhor abordagem. Não tenho certeza de qual abordagem é melhor quando os dados são considerados variáveis em tamanho.
Considere as 3 TABELAS a seguir:
EMPREGADO
EMPLOYEE_ID, EMP_NAME
PROJETO
PROJECT_ID, PROJ_NAME
EMP_PROJ (muitas para muitas das duas tabelas acima)
EMPLOYEE_ID, PROJECT_ID
Problema : Dado um CódigoDoEmpregado, localize TODOS os funcionários de TODOS os Projetos aos quais este Funcionário está associado.
Eu tentei isso de duas maneiras. Ambas as abordagens diferem apenas em alguns milissegundos, independentemente do tamanho dos dados usados.
SELECT EMP_NAME FROM EMPLOYEE
WHERE EMPLOYEE_ID IN (
SELECT EMPLOYEE_ID FROM EMP_PROJ
WHERE PROJECT_ID IN (
SELECT PROJECT_ID FROM EMP_PROJ p, EMPLOYEE e
WHERE p.EMPLOYEE_ID = E.EMPLOYEE_ID
AND E.EMPLOYEE_ID = 123)
ir
select c.EMP_NAME FROM
(SELECT PROJECT_ID FROM EMP_PROJ
WHERE EMPLOYEE_ID = 123) a
JOIN
EMP_PROJ b
ON a.PROJECT_ID = b.PROJECT_ID
JOIN
EMPLOYEE c
ON b.EMPLOYEE_ID = c.EMPLOYEE_ID
A partir de agora, espero cerca de 5000 funcionários e projetos cada .. mas não tenho idéia sobre o tipo de relação entre muitos e muitos. Qual abordagem você recomendaria? obrigado!
EDIT: Plano de Execução da Abordagem 1
"Hash Join (cost=86.55..106.11 rows=200 width=98)"
" Hash Cond: (employee.employee_id = emp_proj.employee_id)"
" -> Seq Scan on employee (cost=0.00..16.10 rows=610 width=102)"
" -> Hash (cost=85.07..85.07 rows=118 width=4)"
" -> HashAggregate (cost=83.89..85.07 rows=118 width=4)"
" -> Hash Semi Join (cost=45.27..83.60 rows=118 width=4)"
" Hash Cond: (emp_proj.project_id = p.project_id)"
" -> Seq Scan on emp_proj (cost=0.00..31.40 rows=2140 width=8)"
" -> Hash (cost=45.13..45.13 rows=11 width=4)"
" -> Nested Loop (cost=0.00..45.13 rows=11 width=4)"
" -> Index Scan using employee_pkey on employee e (cost=0.00..8.27 rows=1 width=4)"
" Index Cond: (employee_id = 123)"
" -> Seq Scan on emp_proj p (cost=0.00..36.75 rows=11 width=8)"
" Filter: (p.employee_id = 123)"
Plano de execução da abordagem 2:
"Nested Loop (cost=60.61..112.29 rows=118 width=98)"
" -> Index Scan using employee_pkey on employee e (cost=0.00..8.27 rows=1 width=4)"
" Index Cond: (employee_id = 123)"
" -> Hash Join (cost=60.61..102.84 rows=118 width=102)"
" Hash Cond: (b.employee_id = c.employee_id)"
" -> Hash Join (cost=36.89..77.49 rows=118 width=8)"
" Hash Cond: (b.project_id = p.project_id)"
" -> Seq Scan on emp_proj b (cost=0.00..31.40 rows=2140 width=8)"
" -> Hash (cost=36.75..36.75 rows=11 width=8)"
" -> Seq Scan on emp_proj p (cost=0.00..36.75 rows=11 width=8)"
" Filter: (employee_id = 123)"
" -> Hash (cost=16.10..16.10 rows=610 width=102)"
" -> Seq Scan on employee c (cost=0.00..16.10 rows=610 width=102)"
Parece que o plano de execução da Abordagem 2 é um pouco melhor, porque o 'custo' é 60 em oposição a 85 da abordagem 1. É o caminho certo para analisar isso?
Como alguém sabe que isso se aplica mesmo para todo tipo de combinação de muitas e muitas?
fonte
explain analyze
pode revelar mais diferenças entre os planosRespostas:
No SQL Server, com algumas suposições como "esses campos não podem conter NULLs", essas consultas devem fornecer quase o mesmo plano.
Mas considere também o tipo de associação que você está fazendo. Uma cláusula IN como essa é uma junção semi, não uma junção interna. Uma junção interna pode projetar em várias linhas, fornecendo duplicatas (comparadas ao uso de IN ou EXISTS). Portanto, convém considerar esse comportamento ao escolher como você escreve sua consulta.
fonte
IN
eEXISTS
sempre dou o mesmo plano na minha experiência.NOT IN
eNOT EXISTS
são diferentes no entanto com oNOT EXISTS
preferido - Algumas comparações de desempenho aquiO que sua consulta está procurando é apenas
ou
fonte
SELECT 1
vez deSELECT *
?Você pode tentar esta consulta:
fonte