J'ai une question sur la meilleure approche. Je ne sais pas quelle approche est la meilleure lorsque les données sont considérées comme de taille variable.
Considérez les 3 TABLEAUX suivants:
EMPLOYÉ
EMPLOYEE_ID, EMP_NAME
PROJET
PROJECT_ID, PROJ_NAME
EMP_PROJ (plusieurs à plusieurs des deux tables ci-dessus)
EMPLOYEE_ID, PROJECT_ID
Problème : étant donné un EmployeeID, recherchez TOUS les employés de TOUS les projets auxquels cet employé est associé.
J'ai essayé cela de deux manières .. les deux approches ne diffèrent que de quelques millisecondes, quelle que soit la taille des données utilisées.
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)
aller
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
Pour l'instant, je m'attends à environ 5000 employés et projets chacun ... mais je n'ai aucune idée de la relation qui existe. Quelle approche recommanderiez-vous? Merci!
EDIT: Plan d'exécution de l'approche 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)"
Plan d'exécution de l'approche 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)"
Il semble donc que le plan d'exécution de l'approche 2 soit légèrement meilleur, car le «coût» est de 60 contre 85 pour l'approche 1. Est-ce la bonne façon d'analyser cela?
Comment sait-on que cela restera vrai même pour toutes sortes de combinaisons plusieurs-plusieurs?
la source
explain analyze
pourrait révéler plus de différences entre les plansRéponses:
Dans SQL Server, avec quelques hypothèses comme «ces champs ne peuvent pas contenir de valeurs NULL», ces requêtes devraient donner le même plan.
Mais considérez également le type de jointure que vous effectuez. Une clause IN comme celle-ci est une semi-jointure, pas une jointure interne. Une jointure interne peut projeter sur plusieurs lignes, donnant ainsi des doublons (par rapport à l'utilisation de IN ou EXISTS). Par conséquent, vous souhaiterez peut-être tenir compte de ce comportement lors du choix de la façon dont vous écrivez votre requête.
la source
IN
etEXISTS
toujours donner le même plan selon mon expérience.NOT IN
etNOT EXISTS
sont différents cependant avecNOT EXISTS
préféré - Quelques comparaisons de performances iciCe que votre requête recherche est juste
ou
la source
SELECT 1
au lieu deSELECT *
?Vous pouvez essayer cette requête:
la source