[mysql] MySQL에서 STRAIGHT_JOIN을 사용하는 경우

작업 중이었던 상당히 복잡한 쿼리가 실행되는 데 8 초가 걸렸습니다. EXPLAIN은 이상한 테이블 순서를 보여 주었고 FORCE INDEX 힌트를 사용하더라도 인덱스가 모두 사용되지 않았습니다. STRAIGHT_JOIN 조인 키워드를 발견하고 일부 INNER JOIN 키워드를이 키워드로 교체하기 시작했습니다. 상당한 속도 향상을 발견했습니다. 결국이 쿼리에 대해 모든 INNER JOIN 키워드를 STRAIGHT_JOIN으로 교체했으며 이제 .01 초 안에 실행됩니다.

제 질문은 언제 STRAIGHT_JOIN을 사용하고 언제 INNER JOIN을 사용합니까? 좋은 쿼리를 작성하는 경우 STRAIGHT_JOIN을 사용하지 않을 이유가 있습니까?



답변

정당한 이유없이 STRAIGHT_JOIN을 사용하지 않는 것이 좋습니다. 내 경험으로는 MySQL 쿼리 최적화 프로그램이 내가 원하는 것보다 더 자주 잘못된 쿼리 계획을 선택하지만 일반적으로이를 우회해야 할만큼 충분하지 않은 것입니다.

내 권장 사항은 모든 쿼리를 일반 JOIN으로 남겨 두는 것입니다. 한 쿼리가 차선의 쿼리 계획을 사용하고 있음을 발견하면 먼저 쿼리를 다시 작성하거나 재구성하여 최적화 프로그램이 더 나은 쿼리 계획을 선택하는지 확인하는 것이 좋습니다. 또한 적어도 innodb의 경우 인덱스 통계가 오래된 것이 아니라는 것을 확인하십시오 ( ANALYZE TABLE ). 이로 인해 최적화 프로그램이 잘못된 쿼리 계획을 선택할 수 있습니다. 일반적으로 옵티 마이저 힌트는 마지막 수단이어야합니다.

쿼리 힌트를 사용하지 않는 또 다른 이유는 데이터 분포가 시간이 지남에 따라 변경되거나 테이블이 커짐에 따라 인덱스 선택성이 변경 될 수 있다는 것입니다. 현재 최적의 쿼리 힌트는 시간이 지남에 따라 차선이 될 수 있습니다. 그러나 최적화 프로그램은 현재 오래된 힌트 때문에 쿼리 계획을 조정할 수 없습니다. 옵티마이 저가 결정을 내 리도록 허용하면 더 유연하게 유지됩니다.


답변

에서 MySQL을 참조 가입 :

“STRAIGHT_JOIN은 왼쪽 테이블이 항상 오른쪽 테이블보다 먼저 읽힌다는 점을 제외하면 JOIN과 유사합니다. 이것은 조인 최적화 프로그램이 테이블을 잘못된 순서로 배치하는 경우에 사용할 수 있습니다.”


답변

다음은 최근에 직장에서 발생한 시나리오입니다.

A, B, C의 세 테이블을 고려하십시오.

A에는 3,000 개의 행이 있습니다. B에는 300,000,000 개의 행이 있습니다. C에는 2,000 개의 행이 있습니다.

외래 키는 B (a_id), B (c_id)로 정의됩니다.

다음과 같은 쿼리가 있다고 가정합니다.

select a.id, c.id
from a
join b on b.a_id = a.id
join c on c.id = b.c_id

내 경험상 MySQL은이 경우 C-> B-> A로 이동할 수 있습니다. C는 A보다 작고 B는 거대하며 모두 동등 조인입니다.

문제는 MySQL이 (C.id와 B.c_id) 대 (A.id와 B.a_id) 사이의 교차점 크기를 반드시 고려하지 않는다는 것입니다. B와 C 사이의 조인이 B만큼 많은 행을 반환하는 경우 매우 잘못된 선택입니다. A로 시작하여 B를 A만큼 많은 행으로 필터링했다면 훨씬 더 나은 선택이었을 것입니다. straight_join이 명령을 다음과 같이 강제하는 데 사용할 수 있습니다.

select a.id, c.id
from a
straight_join b on b.a_id = a.id
join c on c.id = b.c_id

이제 a이전에에 가입해야합니다 b.

일반적으로 결과 집합의 행 수를 최소화하는 순서로 조인을 수행하려고합니다. 따라서 작은 테이블로 시작하여 결과 조인도 작아 지도록 조인하는 것이 이상적입니다. 작은 테이블에서 시작하여 더 큰 테이블에 결합하면 큰 테이블만큼 커지면 모든 것이 배 모양이됩니다.

하지만 통계에 따라 다릅니다. 데이터 분포가 변경되면 계산이 변경 될 수 있습니다. 또한 결합 메커니즘의 구현 세부 사항에 따라 다릅니다.

필자가 본 최악의 경우는 필수 straight_join이거나 공격적인 인덱스 힌팅을 제외하고는 모두 가벼운 필터링을 사용하여 엄격한 정렬 순서로 많은 데이터에 페이지를 매기는 쿼리입니다. MySQL은 정렬보다 필터 및 조인에 인덱스를 사용하는 것을 강력히 선호합니다. 이는 대부분의 사람들이 전체 데이터베이스를 정렬하려고하는 것이 아니라 쿼리에 응답하는 행의 제한된 하위 집합을 가지고 있기 때문에 이치에 맞습니다. 그리고 제한된 하위 집합을 정렬하는 것이 정렬 여부에 관계없이 전체 테이블을 필터링하는 것보다 훨씬 빠릅니다. 아니. 이 경우 인덱싱 된 열이있는 테이블 바로 뒤에 스트레이트 조인을 넣어 고정 된 항목으로 정렬하고 싶었습니다.


답변

MySQL은 복잡한 쿼리에서 조인 순서를 선택하는 데 꼭 필요한 것은 아닙니다. 복잡한 쿼리를 straight_join으로 지정하면 쿼리는 지정된 순서대로 조인을 실행합니다. 테이블을 최소 공통 분모가되도록 먼저 배치하고 straight_join을 지정하면 쿼리 성능을 향상시킬 수 있습니다.


답변

STRAIGHT_JOIN,이 절을 사용하여 JOIN순서를 제어 할 수 있습니다 . 즉, 외부 루프에서 스캔되는 테이블과 내부 루프에있는 테이블을 제어 할 수 있습니다 .


답변

STRAIGHT_JOIN을 사용해야하는 이유를 알려 드리겠습니다.

  • 나는 한 성능 쿼리와 문제를.
  • 쿼리를 단순화하여 쿼리가 갑자기 더 효율적이었습니다.
  • 어떤 특정 부분이 문제를 일으켰는지 알아 내려고했지만 그럴 수 없었습니다. (왼쪽 조인 2 개는 느리고 각각 독립적으로 빠름)
  • 그런 다음 느리고 빠른 쿼리로 EXPLAIN을 실행했습니다 (왼쪽 조인 중 하나를 추가).
  • 놀랍게도 MySQL은 두 쿼리 사이의 JOIN 순서를 완전히 변경했습니다.

따라서 조인 중 하나를 straight_join으로 강제하여 이전 조인을 먼저 읽도록 강제했습니다. 이것은 MySQL이 실행 순서를 변경하는 것을 막고 매력처럼 작동했습니다!


답변

내 짧은 경험에서 STRAIGHT_JOIN쿼리를 30 초에서 100 밀리 초로 줄인 상황 중 하나 는 실행 계획의 첫 번째 테이블이 열 순서가있는 테이블이 아니라는 것입니다.

-- table sales (45000000) rows
-- table stores (3) rows
SELECT whatever
FROM
    sales
    INNER JOIN stores ON sales.storeId = stores.id
ORDER BY sales.date, sales.id
LIMIT 50;
-- there is an index on (date, id)

최적화 치고 선택하면 stores 첫 번째 가 발생할 수 Using index; Using temporary; Using filesort있기 때문에

ORDER BY 또는 GROUP BY에 조인 큐의 첫 번째 테이블이 아닌 테이블의 열이 포함 된 경우 임시 테이블이 생성됩니다.

출처

여기에서 옵티마이 저는 sales먼저 사용하여

sales STRAIGHT_JOIN stores