2011-09-14 5 views
3

저는 파이썬과 MySQL로 비디오 추천 사이트 (뮤직 비디오 용 판도라)를 만들고 있습니다. 내 데이터베이스에 세 개의 테이블이 있습니다.이 MySQL 쿼리의 속도를 높이려면 어떻게해야합니까?

비디오 - 비디오 테이블. 데이터가 변경되지 않습니다. 열은 다음과 같습니다

CREATE TABLE `video` (
    id int(11) NOT NULL AUTO_INCREMENT, 
    website_id smallint(3) unsigned DEFAULT '0', 
    rating_global varchar(128) DEFAULT '0', 
    title varchar(256) DEFAULT NULL, 
    thumb_url text, 
PRIMARY KEY (`id`), 
KEY `websites` (`website_id`), 
KEY `id` (`id`) USING BTREE 
) ENGINE=InnoDB AUTO_INCREMENT=49362 DEFAULT CHARSET=utf8 

video_tag - 태그 각 비디오와 관련된 (속성)의 테이블. 변경되지 않습니다.을 user_rating

CREATE TABLE `video_tag` (
    id int(7) NOT NULL AUTO_INCREMENT, 
    video_id mediumint(7) unsigned DEFAULT '0', 
    tag_id mediumint(7) unsigned DEFAULT '0', 
PRIMARY KEY (`id`), 
KEY `video_id` (`video_id`), 
KEY `tag_id` (`tag_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=562456 DEFAULT CHARSET=utf8 

- 사용자가 각각의 태그를 주신 좋은 또는 나쁜 평가의 테이블. 데이터가 항상 변경됩니다.

CREATE TABLE `user_rating` (
    id int(11) NOT NULL AUTO_INCREMENT, 
    user_id smallint(3) unsigned DEFAULT '0', 
    tag_id int(5) unsigned DEFAULT '0', 
    tag_rating float(10,5) DEFAULT '0', 
PRIMARY KEY (`id`), 
KEY `video` (`tag_id`), 
KEY `user_id` (`user_id`) USING BTREE 
) ENGINE=InnoDB AUTO_INCREMENT=447 DEFAULT CHARSET=utf8 

는 사용자의 기본 설정에 따라, 나는 각 보지 않은 비디오를 득점하고, 시도하고 그들이 가장 좋아하는 것을 예측하고자합니다. 이 동영상이 50,000에 대한 완료하는 데 약 2 초 정도 걸립니다 다음과 같은 대규모 쿼리 결과는 :

SELECT video_tag.video_id, 
     (sum(user_rating.tag_rating) * video.rating_global) as score 

FROM video_tag 
JOIN user_rating ON user_rating.tag_id = video_tag.tag_id 
JOIN video ON video.id = video_tag.video_id 

WHERE user_rating.user_id = 1 AND video.website_id = 2 
AND rating_global > 0 AND video_id NOT IN (1,2,3) GROUP BY video_id 
ORDER BY score DESC LIMIT 20 

나는 필사적으로이보다 효율적으로 만들 필요, 그래서 난 그냥 어떤 최선의 방향에 대한 조언을 찾고 있어요 입니다. 일부 아이디어는 내가 생각했습니다 (세 개의 테이블을 조인 할 수있는 방법을 생각하지 않은 방법)

b)는 파이썬으로 그룹화 및 집계의 더 많은 오프로드

A) 재 작업 내 DB 테이블 구조 (확실하지 그

C)이보다 효율적으로 만드는 당신이 추천 방법)

을 시도하고 속도 계산 시간 (이전 땜질은 .. 어떤 이익을 산출 아직하지 않은 메모리에 비 변경 테이블을 저장) 실제로 빠른 ?

감사합니다.

- 주석의 요청에 따라

, EXPLAIN SELECT ... 쇼 :

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE user_rating ref  video,user_id user_id 3 const 88 Using where; Using temporary; Using filesort 
1 SIMPLE video_tag ref  video_id,tag_id tag_id 4 db.user_rating.tag_id 92 Using where 
1 SIMPLE video  eq_ref PRIMARY,websites,id PRIMARY 4 db.video_tag.video_id 1 Using where 
+0

테이블 구조를 둘러싸 지 않을 수도 있습니다. 커뮤니티에서 어떤 것을 기대 하시겠습니까? – ajreal

+0

제안 해 주셔서 감사합니다. 나는 정보에 압도하고 싶지 않았지만 귀하의 의견에 따라 테이블 구조를 추가했습니다. – thegreatt

+1

스키마에도 데이터 형식 + 인덱스 유형/열이 포함되므로 적절한 스키마를 포함해야합니다. – ajreal

답변

1
  • 변경 숫자 유형으로 * rating_global의 *의 필드 유형 (플로트 또는 정수 중), 그것을 varchar로 할 필요가 없습니다. 개인적으로 나는 모든 등급 필드를 정수로 바꿀 것이고, 나는 float 될 필요가 없다.

  • KEY를 id에 놓으십시오. PRIMARY KEY는 이미 색인되어 있습니다. video.id, rating_global, website_id

  • 숫자가 부족한 참조 (예 : video_id -> video.id)의 정수 길이를 확인하십시오. 이 크기는 동일해야합니다.

내가 쿼리 교체하려면 다음 2 단계 솔루션을 제안 : 정말 빨리 수행 할 후자의 쿼리의

CREATE TEMPORARY TABLE rating_stats ENGINE=MEMORY 
SELECT video_id, SUM(tag_rating) AS tag_rating_sum 
FROM user_rating ur JOIN video_tag vt ON vt.id = ur.tag_id AND ur.user_id=1 
GROUP BY video_id ORDER BY NULL 

SELECT v.id, tag_rating_sum*rating_global AS score FROM video v 
JOIN rating_stats rs ON rs.video_id = v.id 
WHERE v.website_id=2 AND v.rating_global > 0 AND v.id NOT IN (1,2,3) 
ORDER BY score DESC LIMIT 20 

을, 당신은 비디오 테이블 필드에 PRIMARY KEY에 통합 할 수 있습니다 website_id 및 rating_global (아마도 website_id만으로 충분합니다).

또한 이러한 통계와 함께 다른 테이블을 사용할 수 있으며 사용자 로그인/작업 빈도에 따라 동적으로 미리 계산할 수 있습니다. 라이브 결과를 표시하는 대신 캐시 된 데이터를 표시 할 수 있다고 생각합니다. 별 차이가 없어야합니다.

+0

감사합니다. 쿼리가 약 30 %의 속도 향상을 달성했습니다! 나는 그것이 생산에서 살 수 있기 전에 아마 이것을 더 내려야 할 필요가 있음을 알았다. 나는 질의 시간의 약 85 %가 첫 번째 질의 (CREATE TEMPORARY TABLE ..)에 소비되었다는 것을 알아 차리고, 거기에 추가적인 권고가 있다면 나는 감사 할 것이다. – thegreatt

+0

또한 사용자의 최신 투표를 권장 사항에 통합 할 수 있도록 캐시를 피하려고합니다. – thegreatt

+0

니스! 일을 빨리하기 위해 또 다른 변화를 할 수 있습니다. * user_rating.id * 열을 삭제하고 * user_id * 및 * tag_id * 열을 해당 테이블의 기본 조합으로 사용하기 때문에 해당 테이블의 PRIMARY KEY로 변환하십시오. ALTER TABLE'user_rating' PRIMARY KEY 추가 ('tag_id','user_id'). – wisefish

관련 문제