2012-06-07 74 views
4

一旦表被完全填充,我很關心下面的查詢的性能。到目前爲止,它正在開發中,並且與虛擬數據很好地配合。MySQL在連接選擇查詢中的500萬行表

表「adress_zoo」一旦完全填充後將包含大約5億條記錄。 「adress_zoo」表格如下所示:

CREATE TABLE `adress_zoo` 
    (`adress_id` int(11) NOT NULL, `zoo_id` int(11) NOT NULL, 
    UNIQUE KEY `pk` (`adress_id`,`zoo_id`), 
    KEY `adress_id` (`adress_id`)) 
    ENGINE=InnoDB DEFAULT CHARSET=latin1; 

其他表格每個最多包含500條記錄。

完整的查詢看起來是這樣的:

SELECT a.* FROM jos_zoo_item AS a 
    JOIN jos_zoo_search_index AS zsi2 ON zsi2.item_id = a.id 
    WHERE a.id IN ( 

    SELECT r.id FROM ( 

     SELECT zi.id AS id, Max(zi.priority) as prio 
     FROM jos_zoo_item AS zi 
     JOIN jos_zoo_search_index AS zsi ON zsi.item_id = zi.id 
     LEFT JOIN jos_zoo_tag AS zt ON zt.item_id = zi.id 
     JOIN jos_zoo_category_item AS zci ON zci.item_id = zi.id 
     **JOIN adress_zoo AS az ON az.zoo_id = zi.id** 

     WHERE 1=1 
     AND ((zci.category_id != 0 AND (zt.name != 'prolong' OR zt.name is NULL)) 
     OR (zci.category_id = 0 AND zt.name = 'prolong')) 
     AND zi.type = 'telefoni' 
     AND zsi.element_id = '44d3b1fd-40f6-4fd7-9444-7e11643e2cef' 
     AND zsi.value = 'Small' 
     AND zci.category_id > 15 
     **AND az.adress_id = 5** 

     GROUP BY zci.category_id) AS r 
) 

    AND a.application_id = 6 
    AND a.access IN (1,1) 
    AND a.state = 1 
    AND (a.publish_up = '0000-00-00 00:00:00' OR a.publish_up <= '2012-06-07 07:51:26') 
    AND (a.publish_down = '0000-00-00 00:00:00' OR a.publish_down >= '2012-06-07 07:51:26') 
    AND zsi2.element_id = '1c3cd26e-666d-4f8f-a465-b74fffb4cb14' 

    GROUP BY a.id 
    ORDER BY zsi2.value ASC 

查詢通常會返回25條記錄。

根據你的經驗,這個查詢是否可以接受(在3秒內響應)? 我可以做些什麼來優化這個?

正如勸通過@Jack我跑瞭解釋查詢並得到這個:

MySQL EXPLAIN output

+1

偏題:這個問題在下次有人問:「MySQL會在我的龐大的100k記錄表中表現不錯嗎?」時,這個問題將成爲一個很好的參考資料。 – lanzz

回答

2

這部分是一個重要的限制:

az.adress_id = 5 

MySQL將表限定爲僅記錄adress_id匹配之前將其與聲明的其餘部分結合,因此它將取決於您認爲結果集有多大。

順便說一句,你有一個UNIQUE(adress_id, zoo_id)和一個單獨的INDEX。有特別的原因嗎?因爲MySQL的第一部分可以被MySQL用來選擇。

同樣重要的是,使用EXPLAIN來了解MySQL如何「攻擊」您的查詢並返回結果。另請參見:http://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html

+0

Hi @Jack, az.adress_id = X將返回約225條記錄。 好的,所以我可以放棄第二個索引,那太棒了! 在這種情況下innodb與myisam呢? – user1441607

+0

@ user1441607好吧,我已經更新了我的答案,包括一個鏈接到MySQL的'EXPLAIN'功能。 –

+0

再次感謝!我用解釋跑它,它似乎使用鍵可以?在原帖中張貼了一個屏幕截圖。 – user1441607

0

爲了避免子查詢,你可以嘗試重寫查詢爲:

SELECT a.* FROM jos_zoo_item AS a 
    JOIN jos_zoo_search_index AS zsi2 ON zsi2.item_id = a.id 
    INNER JOIN 
    ( 
    SELECT ** distinct ** r.id FROM ( 

     SELECT zi.id AS id, Max(zi.priority) as prio 
     FROM jos_zoo_item AS zi 
     JOIN jos_zoo_search_index AS zsi ON zsi.item_id = zi.id 
     LEFT JOIN jos_zoo_tag AS zt ON zt.item_id = zi.id 
     JOIN jos_zoo_category_item AS zci ON zci.item_id = zi.id 
     **JOIN adress_zoo AS az ON az.zoo_id = zi.id** 

     WHERE 1=1 
     AND ((zci.category_id != 0 AND (zt.name != 'prolong' OR zt.name is NULL)) 
     OR (zci.category_id = 0 AND zt.name = 'prolong')) 
     AND zi.type = 'telefoni' 
     AND zsi.element_id = '44d3b1fd-40f6-4fd7-9444-7e11643e2cef' 
     AND zsi.value = 'Small' 
     AND zci.category_id > 15 
     **AND az.adress_id = 5** 

     GROUP BY zci.category_id) AS r 
) T 
    on a.id = T.id 
    where 
    AND a.application_id = 6 
    AND a.access IN (1,1) 
    AND a.state = 1 
    AND (a.publish_up = '0000-00-00 00:00:00' OR a.publish_up <= '2012-06-07 07:51:26') 
    AND (a.publish_down = '0000-00-00 00:00:00' OR a.publish_down >= '2012-06-07 07:51:26') 
    AND zsi2.element_id = '1c3cd26e-666d-4f8f-a465-b74fffb4cb14' 

    GROUP BY a.id 
    ORDER BY zsi2.value ASC 

這種方法並不對每個候選行執行子查詢。只有在幾毫秒內計算出T時,才能提高性能。

+0

一旦所有數據都可用,我會測試這個「調整」。感謝@danihp的輸入。 – user1441607

+0

不錯,我會準備好收回你的消息。 – danihp