하위 쿼리와 조인


158

다른 회사에서 상속 한 응용 프로그램의 느린 섹션을 리팩터링하여 다음과 같은 하위 쿼리 대신 내부 조인을 사용했습니다.

WHERE id IN (SELECT id FROM ...)

리팩토링 된 쿼리는 약 100 배 빠르게 실행됩니다. (~ 50 초 ~ ~ 0.3) 개선이 필요했지만 왜 그렇게 과감했는지 설명 할 수 있습니까? where 절에 사용 된 열은 모두 색인화되었습니다. SQL은 where 절에서 행마다 한 번씩 쿼리를 실행합니까?

업데이트 -결과 설명 :

차이점은 "where id in ()"쿼리의 두 번째 부분에 있습니다.

2   DEPENDENT SUBQUERY  submission_tags ref st_tag_id   st_tag_id   4   const   2966    Using where

조인이있는 1 개의 색인 행 :

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index


2
중복되지 않습니다. 이 질문은 특히 현저한 성능 차이에 관한 것입니다. 다른 질문은 각 접근 방식의 장단점과 한 접근 방식이 더 대중적으로 보이는 이유에 대해 더 일반적이고 개방적입니다.
Basil Bourque 2016 년

@simhumileco 그것은 개선이 아니며, 차이가 없으며, 저자가 쓴 것과 상반되며 코드 스타일에 대한 편집은 부적절합니다. 코드를 언제 수정해야합니까?
philipxy

안녕하세요 @ philipxy, 저자의 생각을 방해하지는 않았지만 코드 조각을 더 읽기 쉽고 신중하게 작성하려고했습니다.
simhumileco

답변:


160

"상관 된 하위 쿼리"(즉, 포함하는 쿼리의 행에서 얻은 값에 따라 where 조건이 달라지는 쿼리)는 각 행마다 한 번씩 실행됩니다. 상관되지 않은 하위 쿼리 (where 조건이 포함하는 쿼리와 독립적 인 쿼리)는 처음에 한 번 실행됩니다. SQL 엔진은이 구별을 자동으로 만듭니다.

그러나, 그렇습니다. Explain-plan은 더티 디테일을 줄 것입니다.


3
주의하시기 바랍니다 DEPENDENT SUBQUERY수단에게 "상관 하위 쿼리"과 정확히 같은 일을.
Timo

38

조인은 인덱스에서 발생하지만 모든 행에 대해 하위 쿼리를 한 번 실행합니다 .


5
나는 이것이 사실이라고 생각하지 않습니다. SQL 엔진은 하위 쿼리를 한 번만 실행하고 결과를 목록으로 사용해야합니다.
dacracot

8
하위 쿼리가 외부 쿼리와 상관 관계가있는 경우 (데이터 사용) 각 행마다 실행됩니다.
qbeuek

4
이 경우에는 사실 일 수도 있지만 일반적으로는 그렇지 않습니다.
Amy B

1
OP의 EXPLAIN말에 따르면 DEPENDENT SUBQUERY이 행동의 가장 명확한 지표입니다.
Timo


7

각 버전에서 Explain-plan을 실행하면 이유를 알려줍니다.


6

쿼리가 데이터 집합에 대해 실행되기 전에 쿼리 최적화 프로그램을 통해 실행되며 최적화 프로그램은 가능한 빨리 결과 집합에서 많은 튜플 (행)을 제거 할 수있는 방식으로 쿼리를 구성하려고 시도합니다. 하위 쿼리 (특히 불량 쿼리)를 사용하는 경우 외부 쿼리 실행이 시작될 때까지 결과 집합에서 튜플을 제거 할 수없는 경우가 종종 있습니다.

쿼리를 보지 않으면 원본에 대해 나쁜 점을 말하기가 어렵지만 옵티마이 저가 훨씬 나아질 수 없었을 것입니다. 'explain'을 실행하면 데이터 검색을위한 옵티 마이저 방법이 표시됩니다.


4

각 쿼리에 대한 쿼리 계획을보십시오.

inJoin일반적으로 동일한 실행 계획을 사용하여 구현할 수 있으므로 일반적으로 이들 간의 변경 속도가 전혀 없습니다.


3
하하, <3 Sql은 쿼리 계획을 읽는 방법을 모릅니다.
Amy B

4

옵티마이 저는 잘하지 못했습니다. 일반적으로 차이없이 변환 할 수 있으며 옵티마이 저가이를 수행 할 수 있습니다.


4

일반적으로 옵티마이 저의 결과로 하위 쿼리가 조인으로 실행될 수 있다는 것을 알 수 없었습니다.이 경우 테이블의 각 레코드에 대해 하위 쿼리를 실행하는 대신 쿼리하는 테이블에 대해 하위 쿼리의 테이블을 조인합니다. 보다 "엔터프라이즈"데이터베이스 중 일부는이 방법이 더 좋지만 여전히 간혹 누락되기도합니다.


4

이 질문은 다소 일반적이므로 여기에 일반적인 대답이 있습니다.

기본적으로 MySQL에 많은 행이 정렬되어 있으면 쿼리 시간이 더 오래 걸립니다.

이 작업을 수행:

각 쿼리 (조인 쿼리, 서브 쿼리 쿼리)에 대해 EXPLAIN을 실행하고 결과를 여기에 게시하십시오.

이러한 쿼리에 대한 MySQL의 해석의 차이를 보는 것이 모든 사람에게 학습 경험이 될 것이라고 생각합니다.


4

where 하위 쿼리는 반환 된 각 행에 대해 1 개의 쿼리를 실행해야합니다. 내부 조인은 하나의 쿼리 만 실행하면됩니다.


3

하위 쿼리가 "전체 테이블 스캔"을 실행했을 수 있습니다. 즉, 인덱스를 사용하지 않고 기본 쿼리의 위치에서 필터링해야하는 너무 많은 행을 반환합니다.

물론 세부 사항이없는 추측이지만 일반적인 상황입니다.


2

하위 쿼리를 사용하면 각 결과에 대해 두 번째 SELECT를 다시 실행해야하며 각 실행은 일반적으로 1 행을 반환합니다.

조인을 사용하면 두 번째 SELECT는 더 많은 행을 반환하지만 한 번만 실행하면됩니다. 장점은 이제 결과에 참여할 수 있으며, 관계를 결합하면 데이터베이스를 잘 활용할 수 있다는 것입니다. 예를 들어, 옵티마이 저는 이제 인덱스를 더 잘 활용하는 방법을 찾을 수 있습니다.


2

조인은 최소한 Oracle의 SQL 엔진의 기초에 있고 매우 빠르게 실행되지만 IN 절만큼 하위 쿼리는 아닙니다.


1
실제로 본질적으로 나쁘지 않은 곳.
Shawn

2

참조 설명서 ( 14.2.10.11 하위 쿼리를 조인으로 다시 쓰기) 에서 가져옵니다 .

LEFT [OUTER] JOIN은 서버가 서버를 더 잘 최적화 할 수 있기 때문에 동등한 하위 쿼리보다 빠를 수 있습니다. 사실 MySQL 서버에만 국한된 것은 아닙니다.

따라서 하위 쿼리는 LEFT [OUTER] JOINS보다 느릴 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.