2017-05-07 67 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

發佈您的表結構和您輸入的索引。 – gaganshera

+0

除了列出您的表結構和索引外,發佈查詢的說明以顯示它是如何執行的 –

回答

1

這對於數據庫來說是一項複雜的工作,並且您可以做的事情並不多,以便真正有效地獲得結果。您可以嘗試使用覆蓋索引的子查詢來限制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表中的三行:

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 KEYimagesid

image_likes需要INDEX(user_id)並且將對該表進行一次掃描。然後只有3個查找到images

原始查詢必須掃描images的所有行並重復掃描所有image_likes