본 게시물의 내용과 이미지는 도서 Real MySQL의 내용을 재구성하여 작성되었습니다. 저자, 출판사에 의해 저작권 문제 발생시 게시물이 비공개 될 수 있음을 알립니다.
서브 쿼리
서브 쿼리를 사용하면 단위 처리별로 쿼리를 독립시킬 수 있다. 조인처럼 여러 테이블을 섞어두는 형태가 아니라서 쿼리의 가독성도 높아지고, 복잡한 쿼리도 손쉽게 작성할 수 있다. 하지만 MySQL 서버는 서브 쿼리를 최적으로 실행하지 못할 때가 많다. 가장 대표적으로 FROM 절에 사용되는 서브 쿼리나 WHERE 절의 IN (subquery) 구문은 가장 최신 버전 에서도 그다지 효율적이지 않다.
서브 쿼리는 외부 쿼리에서 정의된 칼럼을 참조하는지 여부에 따라 상관 서브 쿼리와 독립 서브 쿼리로 나눌 수 있다.
상관 서브 쿼리 (Correlated subquery)
서브 쿼리 외부에서 정의된 테이블의 칼럼을 참조해서 검색을 수행할 때 상관 서브 쿼리라고 한다. 상관 서브 쿼리는 항상 외부 쿼리가 실행된 후 그 결과값이 전달돼야만 서브 쿼리가 실행될 수 있다. 아래의 예제에서 EXISTS 이하의 서브 쿼리에서는 dept_emp 테이블에서 지정된 기간 내에 부서가 변경된 사원을 검색하고 있다. 상관 서브 쿼리는 외부 쿼리보다 먼저 실행되지 못하기 때문에 일반적으로 상관 서브 쿼리를 포함하는 비교 조건은 범우 지헤나 조건이 아니라 체크 조건으로 사용된다.
SELECT *
FROM employees e
WHERE EXISTS
( SELECT 1
FROM dept_emp de
WHERE de.emp_no=e.emp_no
AND de.from_date BETWEEN '2000-01-01' AND '2011-12-30' )
독립 서브 쿼리(Self-Contained subquery)
아래의 예와 같이 외부 쿼리의 칼럼을 사용하지 않고 서브 쿼리에서 정의된 칼럼만 참조할 때 독립 서브 쿼리라고 한다. 독립 서브 쿼리는 외부의 쿼리와 상관없이 항상 같은 결과를 반환하므로 외부 쿼리보다 먼저 실행되어 외부 쿼리의 검색을 위한 상수로 사용되는 것이 일반적이다. 독립 서브 쿼리가 포함된 비교 조건은 범위 제한 조건으로 사용될 수 있다. 하지만 MySQL에서는 독립 서브 쿼리라 하더라도 효율적으로 처리되지 못할 때가 많다.
SELECT de.dept_no, de.emp_no
FROM dept_emp de
WHERE de.emp_no=(SELECT e.emp_no
FROM employees e
WHERE e.first_name='Georgi' AND e.last_name='Facello' LIMIT 1)
서브 쿼리의 제약 사항
- LIMIT 절과 LOAD DATA INFILE의 파일명에는 사용할 수 없다.
- 서브 쿼리를 IN 연산자와 함께 사용할 때에는 효율적으로 처리되지 못한다.
- IN 연산자 안에서 사용하는 서브 쿼리에는 ORDER BY 와 LIMIT를 동시에 사용할 수 없다.
- FROM 절에 사용하는 서브 쿼리는 상관 서브 쿼리 형태로 사용할 수 없다. 이런 형태의 쿼리는 '칼럼을 인식할 수 없다'라는 오류 메시지를 발생시킨다.
mysql> SELECT *
FROM departments d,
(SELECT * FROM dept_emp de WHERE de.dept_no=d.dept_no ) x
WHERE d.dept_no=x.dept_no LIMIT 10;
ERROR 1054 : Unknown column 'd.dept_no' in 'where clause'
- 서브 쿼리를 이용해 하나의 테이블에 대해 읽고 쓰기를 동시에 할 수 없다.
위 예제는 서브 쿼리를 이용해 departments 테이블을 읽고, 조회된 값을 다시 departments 테이블에 업데이트하는 쿼리다. 실제 읽는 레코드와 변경하는 레코드는 다른 레코드이지만 현재 모든 버전에서는 이를 허용하지 않는다.
하지만 이러한 형태의 구문이 꼭 필요하다면 간단히 MySQL을 속일 수는 있다. departments 테이블을 읽는 서브 쿼리의 결과를 임시 테이블로 저장하도록 쿼리를 변경하는 것이다.