2011-10-05 3 views
1

좋아, 나는 단지 최적화 할 수없는 쿼리가 있습니다. 아마 MySQL에서 너무 많이하고 PHP에 더 많이 위임해야합니다. 쿼리는 약 1 분 정도 소요되지만 실제로는 쿼리가 훨씬 빠릅니다. 아래는 내가 성취하고자하는 것에 대한 아이디어를 줄 수있는 가설적인 구조입니다.쿼리 성능 문제. 이것을 최적화 할 수 있습니까?

현재 사용자가 소유 한 book_id의 목록을 쉼표로 구분 된 형식으로 포함하고있는 PHP 변수 $ bookList가 쿼리에 제공됩니다.

이 예제의 경우 사용자가 자신의 라이브러리 ($ bookList)에 할당 된 70 개의 book_id가 있고 자신의 라이브러리와 가장 많은 도서를 공유하는 상점을 찾고 싶다고 가정합니다. 각 상점에는 70 권의 책이 있지만 20 만 개 이상의 상점이 있습니다. 공통점이 50 % 미만인 상점은 걸러집니다.

표 1 : store_books

store_id: mediumint 
book_id: smallint 
index: store_id 
index: book_id 

표 3] :

id: mediumint 
book_id: smallint 

표 2 my_books 저장

id: mediumint 
name: varchar(50) 
primary: id 

쿼리 : 사전에

SELECT count(s.book_id) AS commonBooks, s.id 
       FROM store_books AS sb 
       INNER JOIN stores AS s ON s.id = sb.id 
       WHERE sb.book_id IN ($bookList) 
       GROUP BY sb.store_id 
       HAVING commonBooks > 35 
       ORDER BY commonBooks 

감사합니다!

+2

내부 조인의 sb.id가 sb.store_id가되는 것을 의미합니까? –

+1

테이블'store_books'에 복합 인덱스가 필요하다고 생각합니다. '(store_id, book_id)' –

+1

또한'count (s.book_id)'를'count (*)'로 대체해야합니다. –

답변

2

@Joe Stefanelli의 대답에서 빌리 자면 임시 테이블을 사용하십시오.
BTW 당신이 bl.book_id

의 기본 인덱스가 있는지 확인 :

SELECT count(*) AS commonBooks, s.id 
FROM store_books AS sb 
INNER JOIN stores AS s ON s.id = sb.store_id -- <<sb.store_id, not sb.id 
WHERE sb.book_id IN (SELECT bl.book_id FROM tempBookList) 
GROUP BY sb.store_id 
HAVING commonBooks > 35 
ORDER BY commonBooks DESC 

그것은 MySQL이 하나의 인덱스를 사용할 수있는 작은 알려진 사실이다 : 조회에 오류가 갖고있는 것 같다 per (sub) select.
당신이 테이블 또한 store_book
count(*)에 복합 인덱스가 있는지 확인은 (때로는)이 쿼리의 MyISAM보다는 InnoDB의에서 빠르게 실행됩니다

Table 2: store_books 

store_id: mediumint 
book_id: smallint 
index: (store_id, book_id) <<-- composite primary index. 
index: (book_id) 

보다 빠른 count(afield)(결코 느린) 이노 때문에 커버 리지 인덱스를 사용하여이 쿼리를 해결할 수 있으며 실제 테이블의 데이터를 읽을 필요가 없습니다.

+0

복합 색인이 PRIMARY가 아니어야하는 이유가 있습니까? 현재이 전체 프로젝트를 INNODB 만 사용해야하는 측의 Symfony로 이식하는 중입니다. 다행히도 도움이 될 것입니다. – IOInterrupt

+0

@IOInterrupt, 복합 인덱스 **가 ** 기본이어야합니다. – Johan

+0

방금 ​​들러서 감사하다고 말하고 싶었습니다. 우선, 실제로 제안을 설명해 주셔서 감사합니다. 이렇게하는 이유에 대한 설명없이 "수행하십시오"라고 말하는 것보다 훨씬 도움이되었습니다. – IOInterrupt

1

개인적으로 $ bookList의 값을 임시 테이블에 추출하고 IN을 해당 임시 테이블에 대한 JOIN으로 바꿉니다.

SELECT count(s.book_id) AS commonBooks, s.id 
       FROM store_books AS sb 
       INNER JOIN stores AS s ON s.id = sb.id 
       INNER JOIN tempBookList AS bl ON sb.book_id = bl.book_id 
       GROUP BY sb.store_id 
       HAVING commonBooks > 35 
       ORDER BY commonBooks 
+0

글쎄, my_books에는 그 ID가 있습니다. IN을 사용하는 것보다 테이블에 조인하는 것이 더 빠를 것이라고 생각하십니까? – IOInterrupt

+0

@IO 인터럽트입니다. 확실히 노력할 가치가 있습니다. –

관련 문제