it-source

MySQL에서 STRAYT_JOIN을 사용하는 경우

criticalcode 2022. 10. 31. 23:59
반응형

MySQL에서 STRAYT_JOIN을 사용하는 경우

작업 중인 매우 복잡한 질문이 있어서 실행하는 데 8초가 걸렸습니다.EXPLIDE가 이상한 테이블 순서를 나타내고 있어서 FORCE INDEX 힌트에도 인덱스가 모두 사용되지 않았습니다.STRAY_JOIN 키워드를 발견하여 INSER JOIN 키워드를 대체하기 시작했습니다.나는 상당한 속도 향상을 알아차렸다.결국 이 쿼리에 대해 모든 INSER JOIN 키워드를 STRAYT_JOIN으로 바꾸면 0.01초 만에 실행됩니다.

질문입니다만, STRAYT_JOIN은 언제, INSER JOIN은 언제 사용합니까?좋은 쿼리를 쓰고 있다면 STRAYT_JOIN을 사용하지 않을 이유가 있습니까?

정당한 이유 없이 STRAYT_JOIN을 사용하는 것은 추천하지 않습니다.MySQL 쿼리 옵티마이저는 제가 원하는 것보다 더 자주 부적절한 쿼리 플랜을 선택하지만, 일반적인 쿼리 플랜을 바이패스해야 할 정도는 아닙니다.이것은 항상 STRAY_JOIN을 사용하고 있는 경우입니다.

모든 쿼리를 일반 JOIN으로 두는 것이 좋습니다.1개의 쿼리가 차선의 쿼리 플랜을 사용하고 있는 것을 발견했을 경우, 우선 쿼리를 재작성 또는 재구축하여 옵티마이저가 더 나은 쿼리 플랜을 선택할지 여부를 확인하는 것이 좋습니다.또한 innodb의 경우 인덱스 통계가 오래된 것(ANYLYZE TABLE)만이 아님을 확인합니다.이로 인해 옵티마이저는 부실한 쿼리 계획을 선택할 수 있습니다.일반적으로 옵티마이저의 힌트는 최후의 수단이 됩니다.

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

최근 직장에서 나온 시나리오입니다.

A, B, C의 3개의 테이블을 생각해 봅시다.

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.

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

통계에 따라 다르긴 하지만요.데이터 분포가 변경되면 계산도 변경될 수 있습니다.또한 가입 메커니즘의 구현 세부사항에 따라 달라집니다.

에서 본 MySQL .straight_join또는 적극적인 인덱스 힌트는 광필터링을 사용하여 엄격한 정렬 순서로 많은 데이터에 대해 페이지를 표시하는 쿼리입니다.MySQL은 필터나 조인보다 인덱스를 사용하는 것을 강하게 선호합니다.대부분의 사용자는 데이터베이스 전체를 정렬하려고 하지 않고 쿼리에 응답하는 행의 서브셋이 한정되어 있기 때문에 정렬 여부에 관계없이 테이블 전체를 필터링하는 것보다 제한된 서브셋을 정렬하는 것이 훨씬 빠릅니다.이 경우 고정된 것에 대해 정렬하고 싶은 인덱스 컬럼이 있는 테이블 바로 뒤에 스트레이트 조인합니다.

MySQL JOIN 참조:

STRAYT_JOIN은 JOIN과 비슷하지만 왼쪽 테이블은 항상 오른쪽 테이블보다 먼저 읽힙니다.이는 조인 옵티마이저가 테이블을 잘못된 순서로 배치하는 경우에 사용할 수 있습니다."

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

STRAIGHT_JOIN이 구를 사용하면, 다음의 명령어를 제어할 수 있습니다.JOINorder: 외부 루프에서 스캔되는 테이블과 내부 루프에서 스캔되는 테이블.

STRAY_JOIN을 사용해야 했던 이유를 설명하겠습니다.

  • 질의에 성능 문제가 있었습니다.
  • 쿼리를 단순화하면 쿼리가 순식간에 효율화됩니다.
  • 어떤 부분이 문제의 원인인지 파악하려고 했지만, 할 수 없었습니다.(왼쪽 조인은 2개씩 느리고 각각 독립적으로 빠릅니다.)
  • 그런 다음 느린 쿼리와 빠른 쿼리를 모두 사용하여 EXPLINE을 실행했습니다(왼쪽 조인 중 하나를 추가).
  • 놀랍게도 MySQL은 두 쿼리 사이의 JOIN 순서를 완전히 변경했습니다.

그 때문에, 1개의 조인을 강제적으로 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에 Join 큐의 첫 번째 테이블 이외의 테이블의 열이 포함되어 있는 경우 임시 테이블이 생성됩니다.

원천

여기서 옵티마이저는 그에게 때리라고 말함으로써 약간의 도움이 필요하다.sales최초 사용

sales STRAIGHT_JOIN stores

쿼리가 다음과 같이 끝나는 경우ORDER BY... LIMIT..., it may be optimal to reformulate the query to trick the optimizer into doing theLIMIT 되기 전에JOIN.

(이 답변은 다음에 대한 질문에만 적용되는 것은 아닙니다.STRAIGHT_JOIN모든 경우에 적용되는 것은 아닙니다.STRAIGHT_JOIN.)

@회계사 »부터 대부분의 경우 고속으로 실행됩니다(또한 힌트가 필요하지 않습니다).

SELECT  whatever
    FROM  ( SELECT id FROM sales
                ORDER BY  date, id
                LIMIT  50
          ) AS x
    JOIN  sales   ON sales.id = x.id
    JOIN  stores  ON sales.storeId = stores.id
    ORDER BY  sales.date, sales.id;

주의:

  • 우선 50개의 ID가 취득됩니다.이 작업은 특히 빠른 속도로 진행됩니다.INDEX(date, id).
  • 그 후 다시 가입합니다.sales를 사용하면 임시 테이블에서 "화이트버"를 운반하지 않고도 50개만 얻을 수 있습니다.
  • 서브쿼리는 정의상 순서부여가 없기 때문에ORDER BY외부 쿼리에서 반복해야 합니다.(Optimizer는 실제로 다른 정렬을 하지 않는 방법을 찾을 수 있습니다.)
  • 네, 더 지저분해요.하지만 보통 그것이 더 빠릅니다.

오늘은 빨라도 내일은 빨라지지 않을 수 있기 때문에 히트 사용은 반대합니다.

조금 오래된 것은 알지만, 여기 시나리오가 있습니다.저는 특정 테이블을 채우기 위해 배치 스크립트를 실행하고 있습니다.어느 시점에서는 쿼리가 매우 느리게 실행되었습니다.특정 레코드에서는 가입 순서가 올바르지 않은 것 같습니다.

  • 올바른 순서

여기에 이미지 설명 입력

  • id를 1씩 늘리면 순서가 엉망이 됩니다.'기타' 필드에 주의하세요.

여기에 이미지 설명 입력

  • strate_join을 사용하면 문제가 해결됩니다.

여기에 이미지 설명 입력

straight_join 실행을 사용하는 동안 약 65초 동안 잘못된 순서가 실행됨(밀리초)

--use 120s, 18 million data
    explain SELECT DISTINCT d.taid
    FROM tvassist_recommend_list_everyday_diverse d, tvassist_taid_all t
    WHERE d.taid = t.taid
      AND t.client_version >= '21004007'
      AND t.utdid IS NOT NULL
      AND d.recommend_day = '20170403'
    LIMIT 0, 10000

--use 3.6s repalce by straight join
 explain SELECT DISTINCT d.taid
    FROM tvassist_recommend_list_everyday_diverse d
    STRAIGHT_JOIN 
      tvassist_taid_all t on d.taid = t.taid 
    WHERE 
     t.client_version >= '21004007'
       AND d.recommend_day = '20170403'

      AND t.utdid IS NOT NULL  
    LIMIT 0, 10000

언급URL : https://stackoverflow.com/questions/512294/when-to-use-straight-join-with-mysql

반응형