Mam pytanie dotyczące najlepszego podejścia. Nie jestem pewien, które podejście jest najlepsze, gdy dane są uważane za zmienne pod względem wielkości.
Rozważ następujące 3 TABELE:
PRACOWNIK
EMPLOYEE_ID, EMP_NAME
PROJEKT
PROJECT_ID, PROJ_NAME
EMP_PROJ (wiele do wielu z powyższych dwóch tabel)
EMPLOYEE_ID, PROJECT_ID
Problem : Biorąc pod uwagę identyfikator pracownika, znajdź WSZYSTKICH pracowników WSZYSTKICH projektów, z którymi ten pracownik jest powiązany.
Próbowałem tego na dwa sposoby ... oba podejścia różnią się tylko o kilka milisekund, bez względu na to, jaki rozmiar danych jest używany.
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)
udać się
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
Na dzień dzisiejszy oczekuję około 5000 pracowników i projektów .. ale nie mam pojęcia o tym, jaki rodzaj relacji istnieje wiele osób. Które podejście poleciłbyś? dzięki!
EDYCJA: Plan realizacji podejścia 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 realizacji podejścia 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)"
Wygląda więc na to, że plan wykonania Podejścia 2 jest nieco lepszy, ponieważ „koszt” wynosi 60, a nie 85 podejścia 1. Czy to właściwy sposób na analizę tego?
Skąd wiadomo, że będzie to prawdą nawet w przypadku wielu kombinacji wielu kombinacji?
źródło
explain analyze
może ujawnić więcej różnic między planamiOdpowiedzi:
W SQL Server, z kilkoma założeniami, takimi jak „te pola nie mogą zawierać wartości NULL”, zapytania te powinny dawać prawie ten sam plan.
Ale również weź pod uwagę rodzaj wykonywanego łączenia. Taka klauzula IN to Semi Join, a nie Internal Join. Sprzężenie wewnętrzne może rzutować na wiele wierszy, dając w ten sposób duplikaty (w porównaniu do użycia IN lub EXISTS). Możesz więc rozważyć to zachowanie przy wyborze sposobu pisania zapytania.
źródło
IN
iEXISTS
zawsze podaj ten sam plan z mojego doświadczenia.NOT IN
iNOT EXISTS
różnią się jednakNOT EXISTS
preferowanymi - Tutaj są niektóre porównania wydajnościTo, czego szuka twoje zapytanie, jest właśnie
lub
źródło
SELECT 1
zamiastSELECT *
?Możesz spróbować tego zapytania:
źródło