2009-10-20 24 views
0

我從這個問題掙扎(再次)與表:how to optimize this query (4 mm tables involved)優化COUNT(*)查詢與4間MM的關係,更大的表


這是一個主表product_table已經經由四個MM的關係查找表mm1mm4。查找表的字段爲uid_local,其中包含product_tableuid_foreign的uid,其中包含結果被過濾的類別的uid。

從提高查詢看起來像這樣性能的上述問題Quassnois建議之後:

SELECT 
COUNT(*) 
FROM 
product_table 
WHERE 
(product_table.partner_id = 0 OR product_table.partner_id = 15) AND 
EXISTS(SELECT NULL FROM mm1 WHERE mm1.uid_local = product_table.uid AND mm1.uid_foreign IN (10, 11, 12, 13, 14, 53)) AND 
EXISTS(SELECT NULL FROM mm2 WHERE mm2.uid_local = product_table.uid AND mm2.uid_foreign IN (7, 8, 9)) AND 
EXISTS(SELECT NULL FROM mm3 WHERE mm3.uid_local = product_table.uid AND mm3.uid_foreign IN (51 ,52)) AND 
EXISTS(SELECT NULL FROM mm4 WHERE mm4.uid_local = product_table.uid AND mm4.uid_foreign IN (15, 16, 17, 18, 19)) 

這返回稍微圍繞10.000行作爲COUNT(*)但它需要>0.5秒用於查詢來執行。這太慢了。

EXPLAIN看起來是這樣的:

id select_type   table   type possible_keys   key   key_len ref  rows Extra 
1 PRIMARY    product_table ref NewIndex    NewIndex 4   const  9430 Using where 
5 DEPENDENT SUBQUERY mm1    ref uid_local,uid_foreign uid_local 4   mm1.uid 5  Using where 
4 DEPENDENT SUBQUERY mm2    ref uid_local,uid_foreign uid_local 4   mm2.uid 2  Using where 
3 DEPENDENT SUBQUERY mm3    ref uid_local,uid_foreign uid_local 4   mm3.uid 3  Using where 
2 DEPENDENT SUBQUERY mm4    ref uid_local,uid_foreign uid_local 4   mm4.uid 6  Using where 

如果我改變product_table.partner_id = 0的東西,返回更少的行即G。幾百個左右的查詢速度非常快(0.015秒)。

所以問題是,COUNT(*)查詢是非常快,如果它只需要計數幾行(100 - 200),但計數較大的結果集(> 10.000行)非常慢。

有關如何解決此問題的任何想法?


幾個事實:

  • 的毫米表對uid_local索引和uid_foreign
  • product_table有一個索引PK和存在的product_table表包含圍繞partner_id
  • 另一個指標30.000行

編輯

IN條款是固定的,查詢可以代替IN (7, 8, 9)樣子IN (7, 9)或數字的其他組合。

回答

0

您可以對查詢的EXISTS部分使用物化視圖。這樣,您可以將IN語句摺疊成單個查詢。然後你只需要在uid創建索引和查詢應採取幾乎沒有時間了:

SELECT 
COUNT(*) 
FROM 
product_table 
WHERE 
(product_table.partner_id = 0 OR product_table.partner_id = 15) AND 
EXISTS(SELECT NULL FROM vmm1 WHERE vmm1.uid_local = product_table.uid) AND 
EXISTS(SELECT NULL FROM vmm2 WHERE vmm2.uid_local = product_table.uid) AND 
EXISTS(SELECT NULL FROM vmm3 WHERE vmm3.uid_local = product_table.uid) AND 
EXISTS(SELECT NULL FROM vmm4 WHERE vmm4.uid_local = product_table.uid) 

缺點:如果你改變了MM-表很多,視圖將需要更新,這將對這些表進行更改較慢。

+0

什麼是物化視圖?查詢是否仍然可以接受參數?用戶通過Web前端選擇IN子句的值。 – Max 2009-10-20 17:46:04

+0

從你的例子中,我收集到IN子句已修復。如果他們可以改變,那麼這是行不通的。 – 2009-10-21 08:15:07

+0

物化視圖是複製到動態表中的視圖。當您更改基礎表中的行時,該表的內容將會改變。 – 2009-10-21 08:16:33

0

請看mysql手冊中的FORCE INDEX。如果您的M2M表中有10k行匹配,優化器可能已經決定掃描表比查詢索引要好,但對於您的情況,可能不是。

+0

但是EXPLAIN輸出表示所有的索引都被使用了,還是我看錯了? – Max 2009-10-21 04:58:57