Ich habe eine Frage zum besten Ansatz. Ich bin nicht sicher, welcher Ansatz am besten ist, wenn Daten als variabel in der Größe angesehen werden.
Betrachten Sie die folgenden 3 Tabellen:
MITARBEITER
EMPLOYEE_ID, EMP_NAME
PROJEKT
PROJECT_ID, PROJ_NAME
EMP_PROJ (viele bis viele der obigen zwei Tabellen)
EMPLOYEE_ID, PROJECT_ID
Problem : Suchen Sie mit einer bestimmten Mitarbeiter-ID nach ALLEN Mitarbeitern ALLER Projekte, denen dieser Mitarbeiter zugeordnet ist.
Ich habe dies auf zwei Arten versucht. Beide Ansätze unterscheiden sich nur um wenige Millisekunden, unabhängig von der Größe der verwendeten Daten.
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)
gehen
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
Ab sofort erwarte ich ungefähr 5000 Mitarbeiter und Projekte pro Person. Ich habe jedoch keine Ahnung, in welcher Beziehung sich viele Menschen befinden. Welchen Ansatz würden Sie empfehlen? Vielen Dank!
BEARBEITEN: Ausführungsplan von Ansatz 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)"
Ausführungsplan von Ansatz 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)"
Sieht also so aus, als wäre der Ausführungsplan von Ansatz 2 etwas besser, da die „Kosten“ bei Ansatz 1 bei 60 gegenüber 85 liegen. Ist das der richtige Weg, dies zu analysieren?
Woher weiß man, dass es auch für viele verschiedene Kombinationen gilt?
quelle
explain analyze
Möglicherweise gibt es weitere Unterschiede zwischen den PlänenAntworten:
In SQL Server sollten diese Abfragen mit einigen Annahmen wie "Diese Felder dürfen keine NULL-Werte enthalten" fast denselben Plan enthalten.
Berücksichtigen Sie aber auch die Art des Joins, den Sie ausführen. Eine IN-Klausel wie diese ist ein Semi-Join, kein Inner-Join. Ein Inner Join kann auf mehrere Zeilen projiziert werden, wodurch Duplikate entstehen (im Vergleich zur Verwendung von IN oder EXISTS). Daher sollten Sie dieses Verhalten berücksichtigen, wenn Sie festlegen, wie Sie Ihre Abfrage schreiben.
quelle
IN
undEXISTS
nach meiner Erfahrung immer den gleichen Plan angeben .NOT IN
undNOT EXISTS
sind jedoch mitNOT EXISTS
Vorzug anders - Einige Leistungsvergleiche hierWas Ihre Anfrage sucht, ist einfach
oder
quelle
SELECT 1
stattSELECT *
?Sie können diese Abfrage versuchen:
quelle