27.4 서브 쿼리 제약
IN
에 대한 서브 쿼리의 최적화는=
연산자 또는IN(
연산자의 경우처럼 효과적이지는 않습니다.value_list
)IN
서브 쿼리의 성능이 부족하다 일반적인 예는 서브 쿼리가 약간 행을 반환하고 외부 쿼리가 서브 쿼리의 결과와 비교하여 여러 행을 반환 할 수 있습니다.이 문제는
IN
서브 쿼리를 사용하는 문은 최적화가 상관 서브 쿼리로 다시 작성할 수 있습니다. 비 상관 서브 쿼리를 사용하여 다음 문에 대해 설명합니다.SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);
최적화가 문을 상관 서브 쿼리로 다시 작성합니다.
SELECT ... FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a);
내부 쿼리와 외부 쿼리가 각각
M
행과N
행을 반환하는 경우, 실행 시간은 비 상관 서브 쿼리의 경우 O (M
+N
)이 아닌 O (M
×N
)입니다.즉,
IN
서브 쿼리는이 서브 쿼리가 반환하는 값과 동일한 값을 나열하는IN(
연산자를 사용하여 생성 된 쿼리보다 훨씬 느려질 수 있습니다.value_list
)일반적으로 테이블을 변경할 수도 하위 쿼리 같은 테이블에서 선택 할 수 없습니다. 예를 들어,이 제한은 다음 형식의 문에 적용됩니다.
DELETE FROM t WHERE ... (SELECT ... FROM t ...); UPDATE t ... WHERE col = (SELECT ... FROM t ...); {INSERT | REPLACE} INTO t (SELECT ... FROM t ...);
예외 :
FROM
절의 변경된 테이블 서브 쿼리를 사용하는 경우 위의 금지 사항은 적용되지 않습니다. 예 :UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t ...) AS _t ...);
여기에서는
FROM
절의 서브 쿼리의 결과를 임시 테이블로 저장되므로t
에서 해당 행은t
에 대한 업데이트가 이루어지기 전에 이미 선택되어 있습니다.행 비교 연산자는 부분적으로 지원되고 있습니다.
의 경우expr
[NOT] INsubquery
expr
은n
튜플 (행 생성자 구문을 사용하여 지정합니다)에 있으며, 서브 쿼리는n
튜플의 행을 반환 할 수 있습니다. 따라서 허용되는 구문은 구체적으로
로 표시됩니다row_constructor
[NOT] INtable_subquery
의 경우expr
op
{ALL|ANY|SOME}subquery
expr
은 스칼라 값에해야 하위 쿼리는 컬럼 서브 쿼리로해야합니다. 복합 컬럼 행을 반환 할 수 없습니다.
즉,
n
튜플 행을 반환하는 서브 쿼리의 경우 다음과 같은 지원되어 있습니다.(
expr_1
, ...,expr_n
) [NOT] INtable_subquery
그러나 다음은 지원되지 않습니다.
(
expr_1
, ...,expr_n
)op
{ALL | ANY | SOME}subquery
IN
행 비교를 지원하고 있는데, 다른 지원되지 않는 이유는IN
이=
비교 및AND
연산의 순서에이를 다시 작성하여 구현되어 있기 때문입니다. 이 방법은ALL
,ANY
,SOME
는 사용할 수 없습니다.FROM
절의 서브 쿼리는 상관 서브 쿼리는 할 수 없습니다. 이 쿼리 실행 중에 모든 실체화 (결과 세트를 생성하도록 평가)되므로 외부 쿼리의 행마다 평가 수 없습니다. MySQL 5.6.3 이전에서는 실체화는 외부 쿼리의 평가 전에 이루어집니다. 5.6.3 이상에서 최적화는 결과가 필요할 때까지 실체화를 감속하고이를 통해 실체화를 피할 수 있습니다. 섹션 8.2.1.18.3 "FROM 절의 서브 쿼리 (파생 테이블)의 최적화" 를 참조하십시오.MySQL은 특정 서브 쿼리 연산자에 서브 쿼리의
LIMIT
를 지원하지 않습니다.mysql>
SELECT * FROM t1
->WHERE s1 IN (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1);
ERROR 1235 (42000) : This version of MySQL does not yet support 'LIMIT & IN / ALL / ANY / SOME subquery'최적화는 서브 쿼리에 대해보다 결합에 대한 더 완성도가 높기 때문에, 종종 서브 쿼리를 사용하는 문은 결합으로 덮어 쓸 경우가 더 효율적으로 실행할 수 있습니다.
IN
서브 쿼리를SELECT DISTINCT
결합으로 다시 작성할 수있는 경우에는 예외가 발생합니다. 예 :SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM T2 WHERE
condition
);이 문은 다음과 같이 작성할 수 있습니다.
SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND
condition
;MySQL은 서브 쿼리에서 행을 테이블에 삽입하는 등의 데이터 변경의 부작용이있는 스토어드 함수를 참조 할 수 있습니다. 예를 들어,
f()
가 행을 삽입 할 경우 다음의 쿼리는 데이터를 변경할 수 있습니다.SELECT ... WHERE x IN (SELECT f () ...);
이 동작은 SQL 표준에 대한 확장입니다. MySQL에서는 최적화 프로그램의 처리 방법의 선택에 따라 특정 쿼리 실행에 대해
f()
가 다른 실행 횟수 될 수 있기 때문에이를 통해 불확실한 결과가 생성 될 수 있습니다.명령문 기반 또는 혼합 형식의 복제의 경우,이 불확실성이 같은 쿼리가 마스터와 슬레이브로 다른 결과를 생성 할 수 있습니다.
MySQL 5.6.3 이전에서는
FROM
절의 서브 쿼리 결과를 임시 테이블에 구체화하여 평가되고이 테이블에서는 인덱스가 사용되지 않습니다. 5.6.3 이상에서 쿼리 실행 속도가 빨라 될 경우 최적화 실체화 된 테이블에 인덱스를 만듭니다. 섹션 8.2.1.18.3 "FROM 절의 서브 쿼리 (파생 테이블)의 최적화" 를 참조하십시오.