2017-05-07 13 views
0

このクエリを使用して時間を減らす方法を教えてもらえますか?このSQLクエリの時間を短縮する方法

このSQLクエリです:クエリ時間を確認するには

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; 

、これが結果です:

# 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') 

示唆してください。

+0

インデックスはありますか? 'created'にインデックスを追加してください。 – abeyaz

+0

どのように実行されているかを示すクエリのEXPLAINを投稿してください。 –

+0

"SHOW CREATE TABLE image_likes;"ここに結果を投稿してください。 'image_id'フィールドにインデックスがあるかどうかは重要です。 – user4035

答えて

1

これはDBの複雑な作業であり、実際に効率的に結果を得ることはあまりありません。カバリングインデックスで動作するサブクエリでIOを制限しようとすることができます。あなたは3つの画像の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 - 200 MBのようなものを消費し、メモリに簡単に収まるはずです。カウントでソートする必要があるテンポラリ・テーブルのサイズも小さくなります。

は、派生テーブル(FROM句のサブクエリ)としてそのクエリを使用してimagesテーブルから3行のみの参加:

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_likesINDEX(user_id)を必要とし、そのテーブルを1回スキャンします。その後、imagesに3回の検索のみ。

元のクエリはimagesのすべての行をスキャンし、すべてimage_likesを繰り返しスキャンする必要がありました。

関連する問題