2012-08-27 5 views
1

나는 다음과 같은 쿼리가 :MySQL의 간단한 쿼리 최적화

SELECT 
    b.item_name, 
    COUNT(distinct c.user_id) AS total_count, 
    AVG(c.item_rating) AS avg_rating 
FROM  item_ratings as c 
INNER JOIN items AS b ON b.item_id = c.item_id 
INNER JOIN users AS u ON u.user_id = c.user_id 
WHERE item_active = 1 AND u.user_valid = 1 
GROUP BY c.item_id 

이 쿼리는 고도로 최적화 된 데이터베이스를 500 초 동안 실행 - 무슨 일이 일어나고 있는지 확실하지합니다.

Indexs

item_ratings - item_user_id, (item_id, user_id), item_rating, item_id 
users - user_id, user_valid 
items - item_id (primary), item_search (item_id, item_name), item_r (parent_id, item_id, item_active) 

테이블 크기

가까운 500 만 개 기록에 item_ratings 테이블, 항목 테이블이 약 200K이며, 사용자가 약 25 만된다.

이 쿼리를 설명한다고 설명 item_active에 인덱스가 있더라도, (모든 200K 행을 반환) 항목의 테이블 정렬을 할 것으로 보인다. 다른 테이블 (item_ratings 및 user)은 모두 올바른 색인을 사용합니다. FULL UPDATES

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE b ALL  PRIMARY,item_id, item_search, item_r NULL NULL NULL 218419 Using where; Using temporary; Using filesort 
1 SIMPLE c ref  item_user_id ,user_id, item_id 4 myDB.b.item_id 29 Using where 
1 SIMPLE u eq_ref PRIMARY,user_valid,user_id PRIMARY  4 myDB.c.user_id 1 Using where 

하드웨어 우분투 10.10 실행 이이 전용 MySQL 서버 상자, RAM의 오순절 16기가바이트을 설명한다. 테이블에 MyISAM이 실행 중입니다.

제안 사항?

+5

실제'EXPLAIN' 출력을 게시하십시오 ... – Wrikken

+1

설명 출력 생성 누락, 생성 테이블 출력 누락, 저장 엔진 정보 누락, 저장 엔진 구성 변수 누락, 실행중인 하드웨어 - 누락 된 정보. 너무 많은 정보가 없으면 어떤 종류의 대답을 줄 수 있는지 실마리가 없습니다. –

+1

이 문제를 해결해 주셔서 죄송합니다. – gregavola

답변

2

정확합니다. 이 쿼리는 8 분이 걸리지 않아야합니다. 한 가지 가능성은 쿼리가 전체 테이블 스캔이되기를 원하기 때문에 인덱스가 실제로 쿼리를 악화시키는 것입니다. 이 문제를 해결하기 전에 다음을 제안합니다.

아마도 사용자 및 항목 테이블에는 고유 ID가 있습니다. 또한 사용자는 주어진 항목에 대해 단 하나의 등급 만 가지고있는 것으로 추정됩니다. 이것이 사실이라면, 당신은 별개의 수를 제거하고 카운트로 교체 할 수 있습니다 :

SELECT b.item_name, COUNT(c.user_id) AS total_count, AVG(c.item_rating) AS avg_rating 
FROM item_ratings as c INNER JOIN 
    items AS b 
    ON b.item_id = c.item_id INNER JOIN 
    users AS u 
    ON u.user_id = c.user_id 
WHERE item_active = 1 AND u.user_valid = 1 
GROUP BY c.item_id 

둘째, "is_active"에 인덱스 없다. 색인이 켜져 있습니다 (parent_id, item_id, item_active). parent_id를 사용하지 않는 검색어이므로이 색인은 사용되지 않습니다.

셋째, 집계 때문에 항목 색인을 통과 한 것처럼 보입니다. 대신 ITEM_ID의 ITEM_NAME을 (를) 원하는 표시하기 때문에, 나는에 의해 그룹을 변경 제안 :

group by c.item_name 

이 그것을 더 나은 쿼리 계획을 생성 할 수 있습니다.

0

item_active 필드의 색인을 사용하더라도 쿼리는 여전히 느리게 실행되었습니다. 이 쿼리는 하루에 한 번만 실행되기 때문에 다른 사용자에게 유용 할 수있는 또 다른 솔루션을 발견했습니다.

내가 기본적으로 그냥에만이 쿼리를 사용하여 활성 맥주의 목록을 뽑아

: 각 행의 다음

SELECT b.beer_name 
FROM items as b 
WHERE b.item_active = 1 

, 나는 통해 루프와 같은 각 활성 항목에 대한 등급 수와 평균 평가를 얻었다 :

SELECT COUNT(DISTINCT c.user_id) AS total_count, AVG(c.item_rating) AS avg_rating 
FROM item_ratings as c 
INNER JOIN users AS u ON u.user_id = c.user_id 
WHERE item_active = 1 AND u.user_valid = 1 and b.item_id = @item_id 

여기서 @item_id는 내가 작성한 PHP 루프의 item_id입니다. 이 후, 나는이 결과를 가져 와서 쿼리를 위해 테이블에 놓습니다. 이 작은 쿼리는 실행하는 데 1 초도 채 걸리지 않으며 다른 테이블을 잠그지 않고 오프 피크 시간에 배치 스타일 형식을 실행할 수 있기 때문에이 솔루션은 저에게 효과적입니다.

제안 해 주신 모든 분들께 감사드립니다.