2012-03-25 2 views
1

MySQL을 읽고, 이해하고 최적화하는 방법을 이해하는 데 여전히 문제가 있습니다. orderby 컬럼에 인덱스를 생성하는 것을 알고 있지만 그게 그 것이다. 따라서 나는 당신이 조정이 쿼리를 나를 도울 수 바라고 :조인을 사용하여 MySQL 쿼리를 최적화하는 데 도움이 필요합니다.

EXPLAIN 
SELECT specie.id, specie.commonname, specie.block_description, maximage.title, 
     maximage.karma, imagefile.file_name, imagefile.width, imagefile.height, 
     imagefile.transferred 
FROM specie 
INNER JOIN specie_map ON specie_map.specie_id = specie.id 
INNER JOIN (
    SELECT * 
    FROM image 
    ORDER BY karma DESC 
) AS maximage ON specie_map.image_id = maximage.id 
INNER JOIN imagefile ON  imagefile.image_id = maximage.id 
         AND imagefile.type = 'small' 
GROUP BY specie.commonname 
ORDER BY commonname ASC 
LIMIT 0 , 24 

어떤이 쿼리가하는 것은 정화를위한 가장 카르마와 사진을 찾을 수 있습니다. 여러 이미지 파일 (형식) 당이 있기 때문에 나는 종의 테이블, 이미지의 테이블 사이의 매핑 테이블과 imagefile 테이블이

http://www.jungledragon.com/species

:이 라이브의 결과를 볼 수 있습니다 영상.

출력 설명 : 정화 테이블

enter image description here

, 나는 그것의 기본 ID와 필드으로 commonname에 인덱스가 있습니다. 이미지 테이블의 경우 이드와 카르마 필드에 인덱스가 있고이 질문과 관련이없는 몇 가지 인덱스가 있습니다.

이 쿼리는 현재 0.8에서 1.1 초가 걸리고 내 생각에는 너무 느립니다. 나는 적당한 색인이 이것을 여러번 가속화 할 것이라는 의혹을 가지고있다. 그러나 나는 어느 것을 모른다.

+0

당신이 종 당 1 항목을 찾고 계십니까 : 당신은 INNER JOIN image와 하위 쿼리를 대체하고 최종 ORDER BY 절에 ORDER BY karma DESC 이동하여 동일한 결과를 얻을 수 있을까? 그리고 그것은 최대 카르마 값을 가진 사람이 될 것입니까? 종, 카르마에 대한 색인으로 시작 하겠지만 종에 대한 참조는 이미지 파일에 표시되지 않습니다. – DRapp

+0

'JOIN'과 관련된 모든 컬럼에 인덱스를 넣으십시오. 내가 본 바로는'specie_map.specie_id'와'imagefile.image_id'에'INDEX'을 넣으면 속도가 올라갈 것입니다. –

+0

@Drapp : 종의리스트와 관련이 있습니다. 각 종에 대해 가장 좋은 이미지가 선택됩니다. – Ferdy

답변

1

하위 쿼리를 제거하면 좋은 방법이 될 것이라고 생각합니다. "설명"결과의 첫 번째 행과 마지막 행을 살펴보십시오. 전체 "이미지"테이블을 임시 테이블에 복사하고 있습니다.

SELECT specie.id, specie.commonname, specie.block_description, maximage.title, 
     maximage.karma, imagefile.file_name, imagefile.width, imagefile.height, 
     imagefile.transferred 
FROM specie 
INNER JOIN specie_map ON specie_map.specie_id = specie.id 
INNER JOIN image AS maximage ON specie_map.image_id = maximage.id 
INNER JOIN imagefile ON  imagefile.image_id = maximage.id 
         AND imagefile.type = 'small' 
GROUP BY specie.commonname 
ORDER BY commonname ASC, karma DESC 
LIMIT 0 , 24 
+0

완벽. 그러면 쿼리 속도가 4 배 빨라집니다! 나는 여전히 왜 그런 질문을 쓰는 것처럼 문제가 가장 큰 결과로 그룹화 되었는가를 어떻게 생각 하느냐에 대해 여전히 고심하고있다. 어쨌든 orderby는 나를 위해 일하지 않았다. 그래서 나는 부질의에 갔다. – Ferdy

1

테이블 구조와 인덱스를 제공 할 수 있다면 더 좋을 것입니다. 당신이 시도하고 무슨 말해 수 있다면이 대안 와서, 그것은 좋은 것 (나는 궁금!) :

SELECT t.*, imf.* FROM (
    SELECT s.*, (SELECT id FROM image WHERE karma = MAX(i.karma) LIMIT 1) AS max_image_id 
    FROM image i 
    INNER JOIN specie_map smap ON smap.image_id = i.id 
    INNER JOIN specie s ON s.id = smap.specie_id 
    GROUP BY s.commonname 
    ORDER BY s.commonname ASC 
    LIMIT 24 
) t INNER JOIN imagefile imf 
ON t.max_image_id = imf.image_id AND imf.type = 'small' 
+0

함께 생각해 주셔서 감사합니다. 위 쿼리의 결과입니다 : # 1242 - 하위 쿼리가 두 개 이상의 행을 반환합니다 – Ferdy

+0

내 대답을 업데이트했습니다. 다시 확인해 주시겠습니까? – wisefish

+0

이제 결과를 얻습니다. 감사합니다. 하위 쿼리가없는 위의 대답은 훨씬 빠르다고 생각합니다. – Ferdy

1

진짜 문제는 MySQL이 설명 최적화 할 필요가 없다는 것입니다. 대개는 쿼리 (또는 여러 쿼리)가 효율적이기를 원하며 EXPLAIN은 쿼리 실행이 예상대로 실행되는지 확인하는 방법입니다.

실행 계획이 어떻게 나타나야하는지, 이유를 이해하고 EXPLAIN 명령의 결과와 비교해야합니다. how indexes in MySQL work을 이해해야 계획이 어떻게 될지 이해하십시오.

효율적인 색인을 사용하기 위해서는 다음과 같은 몇 가지 제한 사항이 있기 때문에 검색어가 까다로운 문제입니다. a) 동시 주문 및 한 테이블의 입력란 및 b) finding the last element in each group 다른 입력란 (후자는 까다로운 작업입니다. 그 자체로서). 데이터베이스가 작기 때문에 현재 쿼리가 다소 빠르지 만 (비록 느리다고 생각할지라도) 행운입니다.

내가 조금 해키 방식으로 쿼리를 (I 각 종 적어도 하나 개의 사진이 있다고 가정) 다시 것 :

SELECT 
    specie.id, specie.commonname, specie.block_description, 
    maximage.title, maximage.karma, 
    imagefile.file_name, imagefile.width, imagefile.height, imagefile.transferred 
FROM (
    SELECT s.id, 
      (SELECT i.id 
      FROM specie_map sm 
      JOIN image i ON sm.image_id = i.id 
      WHERE sm.specie_id = s.id 
      ORDER BY i.karma DESC 
      LIMIT 1) as image_id 
    FROM specie s 
    ORDER BY s.commonname 
    LIMIT 0, 24 
) as ids 
JOIN specie 
    ON ids.id = specie.id 
JOIN image as maximage 
    ON maximage.id = ids.image_id 
JOIN imagefile 
    ON imagefile.image_id = ids.image_id AND imagefile.type = 'small'; 

다음과 같은 인덱스 필요합니다

  • (commonname)specie
  • 에 복합 (specie_id, image_id)specie_map
  • 복합,189,321 image
  • 복합 (image_id, type) 0

imagefile에 페이징 이제 부질 내에 발생한다.

아이디어는 id로만 작동하는 서브 쿼리 내에서 복잡한 계산을 만들고 나머지 부분에 대해서는 상위에서 조인하는 것입니다. 데이터는 부속 조회의 결과 순서대로 정렬됩니다.

관련 문제