mojh7 / real-mysql-study

:orange_book: Real MySQL 8.0 study
0 stars 0 forks source link

2023/02/02 ~ 2023/02/07 #40

Open danbi5228 opened 1 year ago

danbi5228 commented 1 year ago

다음 스터디

2023-02-07 pm 10:00 화요일

정리 범위

danbi5228 commented 1 year ago

11.4.10.2 FROM 절에 사용된 서브쿼리

11.4.10.3 WHERE 절에 사용된 서브쿼리

11.4.10.3.1 동등 또는 크다 작다 비교

11.4.10.3.2 IN 비교 ( IN (subquery) )

11.4.10.3.3 NOT IN 비교 ( NOT IN (subquery) )

mojh7 commented 1 year ago

11.4.10 서브쿼리

서브쿼리를 사용하면

5.6 버전까지는 서브쿼리를 최적으로 실행하지 못할 때가 많았지만

8.0 버전 부터는 서브쿼리 처리가 많이 개선됨

여러 위치에 서브쿼리를 사용할 수 있는데, 대표적으로 SELECT, FROM, WHERE 절에서 사용


11.4.10.1 SELECT 절에 사용된 서브쿼리

서브쿼리가 적절히 인덱스를 사용할 수 있다면 크게 주의할 사항 없음


일반적으로 SELECT 절에 서브쿼리를 사용하면 항상 칼럼과 레코드가 하나인 결과를 반환해야 한다

MySQL에서는 이 체크 조건이 조금은 느슨하다

SELECT emp_no, (SELECT dept_name FROM departments WHERE dept_name='Sales1')
FROM dept_emp LIMIT 10;

해당 서브쿼리는 항상 결과가 0건이지만 에러가 발생하지 않고

서브쿼리의 결과가 NULL로 채워져서 반환됨

SELECT emp_no, (SELECT dept_name FROM departments)
FROM dept_emp LIMIT 10;

서브쿼리가 2건 이상의 레코드를 반환하는 경우에는 에러가 나면서 쿼리가 종료

SELECT emp_no, (SELECT dept_no, dept_nmae FROM departments WHERE dept_name='Sales1')
FROM dept_emp LIMIT 10;

SELECT 절에 사용된 서브쿼리가 2개 이상의 칼럼을 가져오려고 할 때도 에러가 발생


결국 SELECT 절의 서브쿼리에는 로우 서브쿼리를 사용할 수 없고, 오로지 스칼라 서브쿼리만 사용할 수 있다

서브쿼리가 만들어내는 결과에 따라 스칼라 서브쿼리와 로우 서브쿼리로 나뉘어진다

스칼라 서브쿼리

로우 서브쿼리(레코드 서브쿼리)


조인으로 처리해도 되는 쿼리를 SELECT 절의 서브쿼리를 사용해서 작성할 때도 있는데

서브쿼리로 실행될 때 보다 조인으로 처리할 때가 조금 더 빠르다

106p 쿼리를 보면 두 예제 쿼리 모두 employees 테이블을 두 번씩 PK 를 이용해 참조하는 쿼리이고

첫 번째 쿼리는 emp_no PK라서 조인이나 서브쿼리 중 어떤 것을 사용해도 둘 다 같은 결과가 나온다

서브 쿼리를 사용한 첫 번째 쿼리는 평균 0.78초

조인을 사용한 두 번째 쿼리는 0.65초가 나왔는데

처리해야 하는 레코드 건수가 많아질수록 성능차이가 커져서 가능하면 조인으로 쿼리를 작성하는 방법을 권장


SELECT 절에 서브쿼리가 사용되는 경우 동일한 서브쿼리가 여러 번 사용되기도 한다

107p 쿼리에서 LIMIT 1 조건 때문에 salaries 테이블을 조인으로 사용할 수가 없었는데

MySQL 8.0 버전부터 도입된 래터럴 조인을 이용하여 동일한 서브쿼리를 남용하지 않아도 된다

107p 래터럴 조인으로 변경된 쿼리는 salaries 테이블을 한 번만 읽어서 쿼리를 처리할 수 있다


8.0 버전의 래터럴 조인이 가지는 문제점

서브쿼리를 사용하는 쿼리와 래터럴 조인을 사용한 쿼리를 실행했을 때 MySQL 서버의 상태 값 변화를 보면

래터럴 조인은 내부적으로 임시 테이블을 생성하기 때문에 Handler_write 값과 Handler_read_key 값이 증가할 수 있다

서브쿼리를 사용한 경우 테이블을 여러 번 읽기 때문에 Handler_read_key 값이 증가할 수 있는 실행 계획이 맞음

그런데 래터럴 조인을 사용한 쿼리에서 handler_read_next 값이 6이 된 것은 잘못된 것