작성
·
2.8K
0
안녕하세요? 강사님
질문이 있습니다
Outer조인실습02 강의의 8분50초쯤에
city가 Madrid인 고객에 대해서 left join이 실행된다고 강조해주셨습니다
여기서 질문이 저는 sql 실행 순서가 from->where->groupby->... 로 알고 있는데
이 순서가 맞다면 from절에서 전체 고객에 대해 join을 다 수행 한 다음에 그 결과 테이블을 where 절로 city가 Mardrid 인 고객만 필터되는 것이 맞다고 생각드는데
이건 내부적으로 SQL이 최적화하면서 실행 순서를 무시(?)하는 것으로 받아들이면 되는걸까요?
감사합니다
답변 2
2
안녕하십니까,
먼저 sql 의 실행 순서가 from -> where -> groupby 맞는데 짚고 넘어가야 할 부분이 있습니다.
where절이 index 컬럼에 해당되어 index를 타게 되면 where절 조건에 해당하는 데이터만 from 테이블에 가서 access를 하게 됩니다.
예를 들어 select * from table01 where col_01 = 'ABC' 라고 했을 때 table01이 100만건이 있고 col_01이 index가 잡혀있고 10건만 되어 있다면 index로 10건의 데이터만 filtering해서 table01에 access하게 됩니다.
만약 col_01이 인덱스가 잡혀있지 않으면 table01 100만건을 access한 뒤 where조건의 10건의 데이터만 filtering합니다.
조인의 경우는 두개의 테이블을 조인할 경우 where 조건이 있는 테이블이더라도 반드시 먼저 access하지 않을 수도 있습니다. DBMS 내부적으로 가장 조인 연결량이 적은 방향성으로 테이블을 어떻게 먼저 Access 할지 결정하게 됩니다.
하지만 left outer조인을 할 경우에는 일반적으로 왼쪽에 있는 테이블부터 먼저 access가 됩니다. 왜냐하면 왼쪽에 있는 테이블은 조인으로 연결 실패하더라도 그대로 유지가 되어야 하기 때문입니다. (물론 이것도 발전된 DBMS의 경우 내부적으로 조인 연결량이 적은 방향성을 가진 테이블을 먼저 Access하면서도 outer 조인을 유지 할 수도 있습니다)
강의에서 설명드린 아래 sql은 다음과 같은 순서로 풀릴 겁니다. 먼저 집합이 보존되어야 하는 customers 테이블 부터 읽은 뒤 where 조건이 a.city='Madrid' 에 해당하는 선행 집합을 만듭니다. 만약 customers가 100건이고 a.city='Madrid'가 10건이라면 10건의 customers 선행 집합이 만들어 집니다. 10건의 선행 집합은 이후 조인에서 조인이 연결되지 않아도 left outer join이므로 누락되지 않습니다.
그리고 이 집합을 기반으로 nw.orders와 조인을 합니다. 이때 customer와 orders는 customer_id레벨로 1:m이므로 orders 집합 레벨로 데이터가 만들어지지만 앞 선행 집합 10건의 customers중에 주문을 하지 않아서 조인이 되지 않더라도 left outer join으로 그대로 유지가 됩니다. 물론 조인이되지 않는 데이터의 경우 orders컬럼의 값들은 모두 Null 이 되게 됩니다.
이런 식으로 employees, shippers 모두 순차적으로 조인을 수행하게 됩니다. 감사합니다.
select a.customer_id,.......
from nw.customers a
left join nw.orders b on a.customer_id = b.customer_id
left join nw.employees c on b.employee_id = c.employee_id
left join nw.shippers d on b.ship_via = d.shipper_id
where a.city = 'Madrid';
0
안녕하세요. 답변 감사드립니다. 질문한 사람은 아닌데 질문과 답변을 모두 읽고 제가 내린 결론을 좀 확답을 받고싶어서 이렇게 남기게 됬습니다.
저도 질문자님과 똑같이 생각을해서 customers, orders, employees, shippers를 where조건을 고려하지않고 우선 모든 컬럼을 가지고 left join을 하고나서 left join이 최종적으로 된 결과테이블을 가지고 where절 Filter를하여 결과를 내어주는것으로 생각을 했는데
답변주신것을 읽고나서 생각해보니 Madrid가 아닌게 어차피 최종 결과에서 걸러질건데 Mardrid가 아닌 데이터를 굳이 계속 left join을 함에있어서 끌고갈 필요가 없구나라는걸 알게됬습니다.
그리고 customers의 DDL을 확인해보니 city같은 경우에는 Index로 설정되어있지 않은 컬럼이니 만약에 customers에 총 100만개의 Row가 있고, Madrid인 Customer는 100개가 있다고 하면 index가 아닌 Raw Data(생 데이터)를 하나하나 읽어가며 100개를 찾고 그걸가지고 나머지 orders, employees, shippers의 left join을 진행한다라고 이해하면 될까요?
정리하자면,
where 절에 조건이 있다면 일단 필터링을 한번 하고나서 조인을하고 그게 퍼포먼스적으로 더 좋을 확률이 높다.(Optimizer가 어떻게 내부적으로 동작할지는 너무 다양하다 판단해서 "확률이 높다"라고 표현을 했습니다.)
Where절에 있는 컬럼이 Index라면 실제 데이터가 있는 Row까지 접근할 필요는 없고, Index에서만 일일이 찾아서 Join을 수행하고, 그렇지 않다면, 생 데이터를 일일이 찾고 그걸 가지고 Join을 수행한다.
이렇게 두가지 결론을 내게 됬습니다. 제 생각이 맞을까요?
정말 좋은 강의 감사드립니다. 답변 또한 너무 상세하게 해주셔서 매우 큰 도움이 되고 있습니다. 다시한번 감사드립니다.
안녕하십니까,
답변을 드리게 전에 먼저, Table의 데이터를 액세스하는 방법은 Index를 통한 Table 액세스, Table 전체를 Access하는 방법(즉 full table scan)이 있습니다.
두개의 테이블을 조인 수행할 때 맨 처음 액세스 되는 테이블을 물리적인 실행계획으로 표현할 때 보통 드라이빙(Driving) 테이블이라고 합니다(물론 조인의 개념으로만 보면 outer 테이블이라고 표현합니다만, 여기서는 물리적인 액세스를 기준으로 하겠습니다)
이때 DB가 드라이빙 테이블을 결정하는 조건은 여러가지가 있지만, 조인 연결량을 줄여 줄 수 있는 테이블이 어떤 것인지를 판단해서 주로 결정해 줍니다.
만약 where 조건으로 걸러지는 데이터량이 많아서 조인 연결량을 줄여줄 수 있다면 당연히 해당 테이블을 먼저 액세스 할 것입니다. 그리고 where 조건 컬럼에 index가 달려 있다면 index를 액세스하여 대상 건수만 테이블을 액세스 한 뒤 조인으로 연결하며, index가 달려 있지 않다면 전체 테이블을 액세스하여 해당 where 조건으로 filtering 된 건수만 조인으로 연결할 것입니다.
customers에 총 100만개의 Row가 있고, Madrid인 Customer는 100개가 있다고 하면 index가 아닌 Raw Data(생 데이터)를 하나하나 읽어가며 100개를 찾고 그걸가지고 나머지 orders, employees, shippers의 left join을 진행한다라고 이해하면 될까요?
=> 네 맞습니다.
where 절에 조건이 있다면 일단 필터링을 한번 하고나서 조인을하고 그게 퍼포먼스적으로 더 좋을 확률이 높다.(Optimizer가 어떻게 내부적으로 동작할지는 너무 다양하다 판단해서 "확률이 높다"라고 표현을 했습니다.)
=> 반드시 그런건 아니지만 그럴 가능성이 높습니다. where 절 조건이 없는 테이블을 먼저 액세스(드라이빙 테이블로 선정) 해서 조인 성능이 더 좋아 질 수도 있습니다. 가령 where 절 조건이 있는 테이블의 인덱스가 where절 컬럼으로만 index가 되어 있는게 아니라 조인컬럼 + where절 컬럼으로 되어 있을 경우에는 where절 조건이 없는 테이블을 먼저 액세스 하는게 더 좋을 수 있습니다.
Where절에 있는 컬럼이 Index라면 실제 데이터가 있는 Row까지 접근할 필요는 없고, Index에서만 일일이 찾아서 Join을 수행하고, 그렇지 않다면, 생 데이터를 일일이 찾고 그걸 가지고 Join을 수행한다.
=> 네 맞습니다. index가 있다면 해당 index에서 먼저 걸러진 데이터들만 join을 수행하고 index가 없다면 테이블 전체를 access해서 해당 조건으로 걸러낸 뒤 조인을 수행합니다.