2010-08-11 2 views
17

FORCE INDEX (abc) 키워드를 사용하여 MySQL이 쿼리를 실행하는 방식을 변경할 수 있음을 알고 있습니다. 그러나 실행 명령을 변경하는 방법이 있습니까?MySQL 실행 순서를 강제하는 방법이 있습니까?

내 쿼리는 다음과 같습니다

SELECT c.* 
FROM table1 a 
INNER JOIN table2 b ON a.id = b.table1_id 
INNER JOIN table3 c ON b.itemid = c.itemid 
WHERE a.itemtype = 1 
    AND a.busy = 1 
    AND b.something = 0 
    AND b.acolumn = 2 
    AND c.itemid = 123456 

내가 사용하는 모든 관계/제약의 키가 있습니다. 내가이 문장에 대해 설명을하면, mysql이 먼저 쿼리를 시작한다는 것을 알 수있다.

id select_type table type 
1  SIMPLE   c  ref 
2  SIMPLE   b  ref 
3  SIMPLE   a  eq_ref 

는 그러나, 나는 a -> b -> c 빠른 것 순서로 쿼리 특정 순서를 사용하는 mysql을 말할 수있는 방법이 있나요 (I는 것을 증명) 알아?

업데이트 : 이것이 내가 a -> b -> c이 더 빠르다는 것을 알고있는 방법입니다.

위 쿼리는 완료하는 데 1.9 초가 걸리고 7 행을 반환합니다. 내가

SELECT c.* 
FROM table1 a 
INNER JOIN table2 b ON a.id = b.table1_id 
INNER JOIN table3 c ON b.itemid = c.itemid 
WHERE a.itemtype = 1 
    AND a.busy = 1 
    AND b.something = 0 
    AND b.acolumn = 2 
HAVING c.itemid = 123456 

쿼리가 0.01 초에 완료에 쿼리를 변경하는 경우 (가진 사용하지 않고 나는 10.000 행을 얻을). 그러나이 쿼리는 단순화 된 예제이기 때문에 이는 훌륭한 해결책이 아닙니다. 현실 세계에서 나는 c에서 다른 테이블에 조인했습니다. HAVING은 전체 결과에 대해 실행되는 필터이므로 db에서 nescessary보다 많은 magnitues 레코드를 가져옵니다.

Edit2가 : 그냥 몇 가지 정보 :이 쿼리에

  • 변수 부분은 c.itemid이다. 다른 모든 것은 변경되지 않는 고정 값입니다.
  • 인덱스 설정 미세하고 MySQL은 1가 나를 위해 A와 B 사이
    • 를 오른쪽 것들을 선택 : N의 관계 (인덱스 PRIMARY 사용한다) (B) 사이
    • 및 C 많은 많은 존재 관계

점은 MySQL의 테이블 A를 조회 시작하고이 길 아래로 C 및 원형이 아닌 다른 방법 일을해야한다는 것입니다 (인덱스 IDX_ITEMID이 사용됩니다). 그 변화가 생기면

솔루션 : 내가 원하지만이 작동하는 것 같다 아니 정확히 :

SELECT c.* 
FROM table1 a 
INNER JOIN table2 b ON a.id = b.table1_id 
INNER JOIN table3 c ON b.itemid = c.itemid 
WHERE a.itemtype = 1 
    AND a.busy = 1 
    AND b.something = 0 
    AND b.acolumn = 2 
    AND c.itemid = 123456 
    AND f.id IN (
     SELECT DISTINCT table2.id FROM table1 
     INNER JOIN table2 ON table1.id = table2.table1_id 
     WHERE table1.itemtype = 1 AND table1.busy = 1) 
+1

'a -> b -> c'가 더 빠를 것이라고 어떻게 증명 했습니까? 또한 색인을 보여줄 수 있습니까? – Unreason

+0

테스트가 빠르면 실제로 많은 양의 데이터가 미리로드되고 정상적인로드를 시뮬레이트하지 않고 테스트하기가 어려울 수 있습니다. MySQL이 자체 최적화를 수행하는 것이 좋으며, 더 많은 데이터를 얻는 것은 점점 더 정확 해지고 (시간이 지남에 따라 또는 ANALYZE TABLE을 한두 번 실행 함) 문제에 부딪혔을 때만 인덱스를 강제 실행합니다. 그런 문제는 존재한다. 나는 분명히 MySQL의 쿼리 계획이 pathalogically 나쁘지만 특정 인덱스를 강요하고 따라서 주문을 결합한 후 좋고 효율적으로 작동했습니다. – thomasrutter

+0

@thomasrutter : MySQL의 최적화 결과가 2-7 초 (로드/데이터 양에 따라 다름) 쿼리에서 내 최적화를 사용하는 것보다 다른 선택이 없다면 : Hammerite가 제안했습니다. STRAIGHT_JOIN은 내가 원하는 것을 수행하고 1은 쿼리를 고정 시켰습니다 천 번. –

답변

28

아마도 STRAIGHT_JOIN을 사용해야합니다.

http://dev.mysql.com/doc/refman/5.0/en/join.html

STRAIGHT_JOIN

은 왼쪽 테이블이 항상 옳은 테이블 전에 읽을 것을 제외하고, JOIN 유사하다. 이는 조인 옵티 마이저가 테이블을 잘못된 순서로 놓는 경우 (소수의 경우)에 사용할 수 있습니다.

+2

'STRAIGHT_JOIN은 JOIN과 유사합니다. 단, 왼쪽 테이블은 항상 오른쪽 테이블보다 먼저 읽 힙니다. 이것은 조인 옵티마이 저가 잘못된 순서로 테이블을 두는 경우에 사용할 수 있습니다. '이것은 정확하게 내가 검색 한 것입니다. 이제 나의 설명은'a -> b -> c'이고 나는 SUBSELECT가 필요 없다. –

+0

아주 좋습니다. 그러나 이상하게도 STRAIGHT_JOIN은 내부 조인 만 할 수 있고 외부 조인은 할 수 없습니다. http://forums.mysql.com/read.php?115,565624,565668#msg-565668은 이유 (마지막 줄)를 설명하려고 시도하지만 올바르지 않습니다. 옵티마이 저는'LEFT JOIN'의 순서를'EXPLAIN'에서 보듯이 똑같이 바꿀 수 있고 그것들에 대한'STRAIGHT_JOIN' 치료법이없는 것처럼 보입니다. – Timo

2

당신은

  • 가 WHERE 조건의 일부를 가져다로
  • 소개 서브 쿼리 가입 두 가지 방법

    으로 재 작성 시도 할 수 있습니다 필요없는 경우에도

두 가지 모두 planner.

확인해야 할 사항은 stats이 최신 상태인지 확인하는 것입니다.

+1

JOIN에 결과를 추가해도 아무 것도 변경되지 않았지만 b의 행 양을 줄이기 위해 하위 쿼리가 포함되었습니다. 실행 계획은 여전히'c -> b -> a '를 보여 주지만 그것이 작동하는 것 같습니다 (업데이트 된 질문을보십시오). –

+0

JOIN에 조건을 추가해도 아무 것도 향상되지 않습니다. 이를 관찰하려면 "explain extended"와 함께 쿼리를 미리 보류 한 다음 쿼리 뒤에 "show warnings;"를 추가하십시오. 경고 표시는 쿼리를 최적화 엔진이 "최적화 된"것으로 표시합니다. 모든 JOIN 요구 사항을 가장 가까운 바운드 WHERE 절로 이동합니다 ... – Nick

2

FORCE INDEX를 사용하여 실행 순서를 강제로 수행 할 수 있습니다.

생각해 보면 보통 선택한 색인에 대해 표를 쿼리 할 수있는 순서는 하나뿐입니다.

이 경우 먼저 MySQL에서 a을 쿼리하기 시작한 경우 b에 강제로 적용되는 인덱스가 b.table1_id 인 인덱스인지 확인하십시오. MySQL은 이미 a이 먼저 쿼리 된 경우에만 해당 인덱스를 사용할 수 있습니다.

+0

+1 좋은 답변입니다. – Unreason

+0

@Unreason, 왜? 위의 다른 대답은 좋은 대답입니다. – Pacerier

+1

어떤 경우에는 기존 조인을 수정할 수 없으므로 강제 색인과 같은 추가 조건을 추가 할 수 있습니다. –