У меня есть вопрос о лучшем подходе. Я не уверен, какой подход лучше, когда данные считаются переменными по размеру.
Рассмотрим следующие 3 ТАБЛИЦЫ:
СОТРУДНИК
EMPLOYEE_ID, EMP_NAME
ПРОЕКТ
PROJECT_ID, PROJ_NAME
EMP_PROJ (много ко многим из двух таблиц выше)
EMPLOYEE_ID, PROJECT_ID
Проблема : По заданному идентификатору сотрудника найдите ВСЕХ сотрудников ВСЕХ проектов, с которыми связан данный Сотрудник.
Я попробовал это двумя способами ... оба подхода отличаются только на несколько миллисекунд, независимо от того, какой размер данных используется.
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)
идти
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
На данный момент я ожидаю около 5000 сотрудников и проектов каждый ... но понятия не имею, какие существуют отношения между многими и многими. Какой подход вы бы порекомендовали? Благодарность!
РЕДАКТИРОВАТЬ: План выполнения подхода 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)"
План выполнения подхода 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)"
Похоже, план выполнения подхода 2 немного лучше, потому что «стоимость» равна 60, а не 85 подхода 1. Это правильный способ проанализировать это?
Как можно знать, что это будет справедливо даже для всех видов множества комбинаций?
источник
explain analyze
может выявить больше различий между планамиОтветы:
В SQL Server с некоторыми допущениями, такими как «эти поля не могут содержать значения NULL», эти запросы должны давать почти тот же план.
Но также рассмотрите тип соединения, которое вы делаете. Предложение IN, подобное этому, является Semi Join, а не Inner Join. Внутреннее соединение может проецироваться на несколько строк, что дает дубликаты (по сравнению с использованием IN или EXISTS). Таким образом, вы можете рассмотреть это поведение при выборе способа написания запроса.
источник
IN
иEXISTS
всегда дают один и тот же план по моему опыту.NOT IN
иNOT EXISTS
отличаются, однако сNOT EXISTS
предпочтением - Некоторые сравнения производительности здесьТо, что ищет ваш запрос, просто
или
источник
SELECT 1
вместоSELECT *
?Вы можете попробовать этот запрос:
источник