2017-05-07 9 views
0

이 쿼리를 사용하여 시간을 절약하려면 어떻게해야합니까? 이 SQL 쿼리의 시간을 단축하는 방법

는 SQL 쿼리입니다 :

# Query_time: 9.948511 Lock_time: 0.000181 Rows_sent: 3 Rows_examined: 4730490 
# Rows_affected: 0 

image_likes :

id (Primary) int(11) 
local_file varchar(100) 
orig_name varchar(100) 
remote_file varchar(1000) 
remote_file_big varchar(1000) 
remote_page varchar(1000) 
image_name varchar(50) 
image_name_eng varchar(50) 
user_idIndex int(11) 
author varchar(50) 
credit varchar(250) 
credit_eng varchar(250) 
location varchar(50) 
description varchar(500) 
description_eng varchar(275) 
notes varchar(550) 
categoryIndex int(11) 
date_range varchar(50) 
createdIndex datetime 
license enum('1', '2', '3') 
status enum('0', '1', '2', '3', '4') 
locked enum('0', '1') 
watch_list enum('0', '1', '2') 
url_title varchar(100) 
url_data varchar(8192) 
rem_date  datetime 
rem_notes varchar(500) 
original_url varchar(1000) 
prevent_sync enum('0', '1') 
checked_by int(11) 
system_recommended enum('0', '1') 

제안하십시오

SELECT 
    `i`.`id`, 
    `i`.`local_file`, 
    `i`.`remote_file`, 
    `i`.`remote_file_big`, 
    `i`.`image_name`, 
    `i`.`description`, 
    IF(`i`.`prevent_sync`='1', '5', `i`.`status`) `status`, 
    GROUP_CONCAT(`il`.`user_id` SEPARATOR ',') AS `likes`, 
    COUNT(`il`.`user_id`) AS `likes_count` 
FROM `images` `i` 
LEFT JOIN `image_likes` `il` ON (`il`.`image_id`=`i`.`id`) 
WHERE 1 AND `i`.`created` < DATE_SUB(CURDATE(), INTERVAL 48 HOUR) 
GROUP BY `i`.`id` 
ORDER BY `likes_count` DESC LIMIT 3 OFFSET 0; 

쿼리 시간을 확인에서이 결과입니다.

+0

색인이 있습니까? 'created'에 인덱스를 추가해야합니다. – abeyaz

+0

쿼리의 EXPLAIN을 게시하여 실행 상태를 표시합니다. –

+0

"SHOW CREATE TABLE image_likes;" 여기에 결과를 게시하십시오. 'image_id' 필드에 인덱스가 있는지 여부를 확인하는 것이 중요합니다. – user4035

답변

1

이것은 DB에 대한 복잡한 작업이므로 결과를 실제로 효율적으로 얻으려면 할 수있는 일이 많지 않습니다. 커버 리지 인덱스에서 작동하는 하위 쿼리로 IO를 제한 할 수 있습니다. 당신은 세 가지 이미지 ID를 얻을 필요가 없습니다 쿼리에서 모든 것을 제거

SELECT i.id 
FROM images i 
JOIN image_likes il ON il.image_id = i.id 
WHERE i.created < DATE_SUB(CURDATE(), INTERVAL 48 HOUR) 
GROUP BY i.id 
ORDER BY COUNT(il.image_id) DESC 
LIMIT 3 OFFSET 0 

작은 커버 인덱스는 images(created, id)image_likes(image_id) 될 것이다. 좋아하는 5M을 사용하면 두 인덱스가 함께 100 - 200MB를 소비하므로 쉽게 메모리에 맞춰야합니다. 카운트별로 정렬해야하는 임시 테이블의 크기도 작아집니다. images 테이블에서 단 세 행을 파생 테이블로 (FROM 절에서 서브 쿼리) 쿼리에 가입

사용 : 그것은 충분히 빨리하지 않으면

SELECT 
    `i`.`id`, 
    `i`.`local_file`, 
    `i`.`remote_file`, 
    `i`.`remote_file_big`, 
    `i`.`image_name`, 
    `i`.`description`, 
    IF(`i`.`prevent_sync`='1', '5', `i`.`status`) `status`, 
    GROUP_CONCAT(`il`.`user_id` SEPARATOR ',') AS `likes`, 
    COUNT(`il`.`user_id`) AS `likes_count` 
FROM (
    SELECT i.id 
    FROM images i 
    JOIN image_likes il ON il.image_id = i.id 
    WHERE i.created < DATE_SUB(CURDATE(), INTERVAL 48 HOUR) 
    GROUP BY i.id 
    ORDER BY COUNT(il.image_id) DESC 
    LIMIT 3 OFFSET 0 
) sub 
JOIN images i ON i.id = sub.id 
JOIN image_likes il ON il.image_id = i.id 
GROUP BY i.id 
ORDER BY likes_count; 

, 당신은 likes_count 사용하여 트리거를 캐시한다.

0

이것은 종종 JOIN + GROUP BY으로 발생하는 "팽창 - 수축"증후군을 앓고 있습니다. 또한 일반적으로 잘못된 집계 값으로 연결됩니다.

SELECT `id`, `local_file`, `remote_file`, 
     `remote_file_big`, `image_name`, `description`, 
     IF(`prevent_sync`='1', '5', `status`) `status`, 
     s.likes, s.likes_count 
    FROM `images` AS `i` 
    JOIN 
     (SELECT GROUP_CONCAT(user_id SEPARATOR ',') AS likes, 
        COUNT(*) AS likes_count 
       FROM  `image_likes` 
       GROUP BY image_id 
       ORDER BY `likes_count` DESC 
       LIMIT 3 OFFSET 0; 
     ) AS s ON s.`image_id`=`i`.`id` 
    WHERE `created` < CURDATE() - INTERVAL 2 DAY 
    ORDER BY `likes_count` DESC; 

이 변형은 likes_count = 0 인 행을 제외하지만 이는 합리적인 것처럼 보입니다.

PRIMARY KEYimages 인 것으로 가정하면 id입니다.

image_likes은 이 필요하며 해당 테이블을 한 번 스캔합니다. 그런 다음 images에 3 번만 조회합니다.

원래 쿼리는 images의 모든 행을 검색하고 image_likes을 반복적으로 스캔해야했습니다.