2017-04-04 39 views
2

我試圖優化以下隱式連接在EXPLAIN行較少,但運行速度比慢明確的JOIN

SELECT `publisher_id`, `publisher_name`, SUM(`views`) AS `total_views`, SUM(`channels`) AS `total_channels` 
FROM (
    SELECT DISTINCT `name` AS `publisher_name`, `id` AS `publisher_id` 
    FROM `publishers` 
    WHERE TRIM(`name`) <> '' 
    ) AS `publisher_names` 
    INNER JOIN 
    (
    SELECT `twitch_name`, `publishers` 
    FROM `game_profiles` 
    WHERE `twitch_name` IS NOT NULL 
     AND `publishers` IS NOT NULL 
     AND TRIM(`publishers`) <> '' 
    ) AS `game_list` 
    ON `game_list`.`publishers` LIKE CONCAT('%', `publisher_names`.`publisher_name`, '%') 
    INNER JOIN 
    (
    SELECT `games`.`id` AS `id`, `games`.`name`, `games`.`simple_name`, `games`.`box`, SUM(`channels`) AS `channels`, SUM(`viewers`) AS `views` 
    FROM `games` 
    WHERE `log_date` >= SUBDATE(NOW(), INTERVAL 1 WEEK) 
     AND `log_date` <= SUBDATE(NOW(), INTERVAL 0 WEEK) 
    GROUP BY `games`.`id` 
    ) AS `view_list` 
    ON `game_list`.`twitch_name` = `view_list`.`name` 
GROUP BY `publisher_id` ORDER BY `total_views` DESC LIMIT 10; 

檢查與查詢性能的查詢說明命令,我得到如下結果。

EXPLAIN result for explicit JOIN

基本上遊戲表中包含的意見,以小時爲單位的信道的數量,在game_profiles表遊戲映射到其publiisher(S),以及出版商表包含每個現有發佈者的更詳細的行。我試圖實現的是根據過去一週遊戲的總視圖來顯示排名前10位的發佈商。

用盡想法,我嘗試使用隱式JOIN。查詢如下

SELECT `publishers`.`id` AS `publisher_id`, `publishers`.`name` AS `publisher_name`, 
SUM(`games`.`viewers`) AS `total_views`, SUM(`games`.`channels`) AS `total_channels` 
FROM `game_profiles`, `publishers`, `games` 
WHERE `game_profiles`.`twitch_name` IS NOT NULL 
    AND `game_profiles`.`publishers` IS NOT NULL AND TRIM(`game_profiles`.`publishers`) <> '' 
    AND `game_profiles`.`publishers` LIKE CONCAT('%', `publishers`.`name`, '%') 
    AND `game_profiles`.`twitch_name` = `games`.`name` 
    AND `games`.`log_date` >= SUBDATE(NOW(), INTERVAL 1 WEEK) 
    AND `games`.`log_date` <= SUBDATE(NOW(), INTERVAL 0 WEEK) 
GROUP BY `publisher_id` ORDER BY `total_views` DESC LIMIT 10; 

寫這使我對以下結果EXPLAIN命令。

EXPLAIN result for implicit JOIN

據我所知,這應該是返回相同的結果,但查詢運行在MySQL工作臺慢,我不能等待它的結果,所以我無法驗證,它實際上回報相同的行。只是從EXPLAIN結果來看,我認爲後者的查詢應該運行得更快。有什麼我在這裏失蹤,爲什麼不是這樣嗎?非常感謝你。

P.S.我的數據庫設計並不是最佳的。這更像是一個原型數據庫。做這個時沒有進行標準化。我只是想更好地瞭解我的查詢中發生了什麼。謝謝。

+2

你寫的SQL代碼很亂方式(格式不正確),所以這不是簡單容易理解......請遵循正確的格式化標準,然後更新您的問題 –

+0

感謝您的編輯@AnkitAgrawal – iron59

回答

2

在第二個查詢中,您正在執行隱式的CROSS JOIN,這是不可取的,並導致您的查詢永遠運行。這意味着首先從所有表中選擇所有行,然後在該操作之後過濾結果集。

至於第一個查詢。

您的數據庫設計不太好。

條款game_list.publishers LIKE CONCAT('%', publisher_names.publisher_name, '%'遠非最佳。應該有一個相當的鏈接表。

所以可能索引也很差,檢查丟失的索引,特別是games表,列log_date

WHERE log_date >= SUBDATE(NOW(), INTERVAL 1 WEEK) 
    AND log_date <= SUBDATE(NOW(), INTERVAL 0 WEEK) 

順便說一句可以使用BETWEEN更好的可讀性rewitten:

WHERE log_date BETWEEN SUBDATE(NOW(), INTERVAL 1 WEEK) 
        AND SUBDATE(NOW(), INTERVAL 0 WEEK) 

LTRIM(publishers) <> ''sargable,儘量避免。 publishers <> ''應該足夠了。

最後INNER JOIN中的表games的分組可能也不是最優的。對於這樣的問題,最好提供SQL Fiddle樣本數據。

但是你在所有子查詢中總是犯一個錯誤。您使用INNER JOIN (SELECT x WHERE y) as Z ON z.something = a.something。這會殺死索引性能。

優化的查詢看起來類似的東西(未驗證):

SELECT 
    publisher_names.id AS publisher_id 
    ,publisher_names.name AS publisher_name 
    ,SUM(view_list.views) AS total_views 
    ,SUM(view_list.channels) AS total_channels 
FROM publishers AS publisher_names 
INNER JOIN game_profiles AS game_list ON 
    twitch_name IS NOT NULL 
    AND publishers IS NOT NULL 
    AND publishers <> '' 
    AND publishers LIKE CONCAT('%', publisher_names.publisher_name, '%') 
INNER JOIN games AS view_list 
     ON log_date BETWEEN SUBDATE(NOW(), INTERVAL 1 WEEK) 
        AND SUBDATE(NOW(), INTERVAL 0 WEEK)   
      AND game_list.twitch_name = view_list.name 
WHERE publisher_names.name <> '' 
GROUP BY publisher_id 
ORDER BY total_views DESC 
+0

是的,我的數據庫設計並不是最佳的。這更像是一個原型數據庫。做這個時沒有進行標準化。我只是想更好地瞭解我的查詢中發生了什麼。感謝您的答覆。我正在查看您現在與您的答案分享的信息。 – iron59

+0

我不知道我在做什麼是一個隱式的CROSS JOIN。我認爲這是一個隱含的INNER JOIN。感謝您的答覆。 – iron59

相關問題