SQL JOIN 또는 IN 절을 사용해야합니까?


13

최선의 접근 방식에 대한 질문이 있습니다. 데이터 크기가 가변적이라고 생각 될 때 어떤 접근법이 최선인지 잘 모르겠습니다.

다음 3 개의 표를 고려하십시오.

종업원

EMPLOYEE_ID, EMP_NAME

계획

PROJECT_ID, PROJ_NAME

EMP_PROJ (위의 두 테이블 중 다수에서 다수)

EMPLOYEE_ID, PROJECT_ID

문제점 : 직원 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의 실행 계획은 접근 방식 1의 85가 아니라 '비용'이 60이기 때문에 약간 더 나은 것처럼 보입니다. 이것이 이것을 분석하는 올바른 방법입니까?

모든 종류의 많은 조합에서도 그렇다는 것을 어떻게 알 수 있습니까?


3
Postgres 설명 계획처럼 보입니다. 개인적으로 조인 기반 접근 방식을 사용하지만 쿼리 다시 작성에 대한 아래 답변 중 일부를 읽으십시오. 아, 그리고 나는 OP 사용 설명을 설명하는 것이 아니라 설명 분석을 제안합니다.
xzilla

나는 xzilla에 동의 : explain analyze더 계획의 차이 밝힐 수
a_horse_with_no_name을

답변:


14

SQL Server에서 "이 필드에는 NULL을 포함 할 수 없습니다"와 같은 몇 가지 가정이 있지만 이러한 쿼리는 거의 동일한 계획을 제공해야합니다.

또한 참여하는 참여 유형도 고려하십시오. 이와 같은 IN 절은 내부 조인이 아닌 세미 조인입니다. 내부 조인은 여러 행에 투영되어 IN 또는 EXISTS를 사용하는 것과 비교하여 중복을 제공 할 수 있습니다. 따라서 쿼리 작성 방법을 선택할 때이 동작을 고려할 수 있습니다.


2
중복 복제를 시도 할 때 조인이 아닌 존재를 사용하는 데 동의합니다. SQL 서버에 대한 내 경험으로는 존재하고 내부 조인은 어쨌든 동일한 쿼리 계획을 생성했습니다. 'in'문에 대한 성능 문제가 있었지만 in 문에서 select가 수천 행을 반환하기 시작했을 때만 나타납니다.
GrumpyMonkey

6
@GrumpyMonkey -에서 SQL 서버 2005 + INEXISTS항상 내 경험에서 같은 계획을 제공합니다. NOT IN그리고 NOT EXISTS와 그러나 다른 NOT EXISTS선호 - 일부 성능 비교 여기
마틴 스미스

8

귀하의 검색어가 찾고있는 것은

SELECT EMP_NAME 
FROM EMPLOYEE e
WHERE E.EMPLOYEE_ID = 123
and exists (select * from EMP_PROJ  where  EMPLOYEE_ID = 123);

또는

SELECT EMP_NAME 
FROM EMPLOYEE e
WHERE E.EMPLOYEE_ID = 123
and exists (select * from EMP_PROJ ep where  ep.EMPLOYEE_ID = E.EMPLOYEE_ID );

하위 쿼리가 SELECT 1아닌 경우 하위 쿼리가 더 빠르지 SELECT *않습니까?
Daniel Serodio

DBMS에 따라 달라질 수 있습니다. SQL-Server가 Select *를 최적화하고 있음을 알고 있습니다. (cf. Microsoft® SQL Server® 2012 T-SQL 기초의 Itzik Ben-Gan)
bernd_k

0

이 쿼리를 시도 할 수 있습니다 :


select distinct e2.employee_id, ep.project_id 
from employee e, employee e2, emp_proj ep
where
e.employee_id = 123
and e.employee_id = ep.employee_id
and e2.project_id = ep.project_id;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.