2013-10-18 84 views
7

我有我想要優化這個大的查詢,我已經優化的,但它仍然是慢了一些次(> 1秒):MySQL的慢大型查詢

select count(DISTINCT if(ps15.specification in ('All Season'),p.products_id,NULL)) as count1 ,count(DISTINCT if(ps15.specification in ('Winter'),p.products_id,NULL)) as count2 ,count(DISTINCT if(ps15.specification in ('Zomer'),p.products_id,NULL)) as count3 ,count(DISTINCT if(ps15.specification in ('Winter 2012'),p.products_id,NULL)) as count4 ,count(DISTINCT if(ps15.specification in ('Zomer 2013'),p.products_id,NULL)) as count5 ,count(DISTINCT if(ps15.specification in ('Winter 2013'),p.products_id,NULL)) as count6 ,count(DISTINCT if(ps15.specification in ('Zomer 2014'),p.products_id,NULL)) as count7 
from (products p) 
inner join (products_to_categories p2c) 
    on (p.products_id = p2c.products_id) 
inner join (products_attributes pa) 
    on (p.products_id = pa.products_id) 
inner join (products_options_values pv) 
    on (pa.options_values_id = pv.products_options_values_id) 
inner join (products_stock ps) 
    on (p.products_id=ps.products_id 
    and pv.products_options_values_id = ps.products_options_values_id2 
    and ps.products_stock_quantity>0) 
INNER JOIN products_specifications ps15 
    ON p.products_id = ps15.products_id 
    AND ps15.specifications_id = '15' 
    AND ps15.language_id = '1' 
INNER JOIN products_specifications ps10 
    ON p.products_id = ps10.products_id 
    AND ps10.specifications_id = '10' 
    AND ps10.language_id = '1' 
where p.products_status = '1' 
    and p2c.categories_id in (72,1,23,100,74,24,33,34,35,77,110,25,45,44,40,41,42,85,76,78,83,102,107,111,119,50,52,81,105,108,112,86,88,87,98,89,90,91,96,79,2,54,60,82,109,115,118,53,58,104,55,101,75,56,64,66,67,68,69,70,71,84,103,114,120,80,92,99,93,94,95,97,106,121) 
    AND ps10.specification in ('Meisje') 
    and products_options_values_name in (62,"3M/60cm","56-62","0-4 mnd","3m","0-3m","3-6m","3M","62/68","0-6m","50-62" , 68,"6M/67cm","9M/70cm","4-8 mnd","6m","3-6m","6M","62/68","0-6m" , 74,"4-8 mnd","8-12 mnd","6m","9m","6-9m","6M","9M","74/80","6-12m"); 

輸出爲:

+--------+--------+--------+--------+--------+--------+--------+ 
| count1 | count2 | count3 | count4 | count5 | count6 | count7 | 
+--------+--------+--------+--------+--------+--------+--------+ 
|  1 | 289 | 193 |  49 | 192 | 240 |  0 | 
+--------+--------+--------+--------+--------+--------+--------+ 

講解MySQL的輸出:

+----+-------------+-------+-------+-------------------------------------------+-------------------------------------+---------+---------------------------------------+------+--------------------------+ 
| id | select_type | table | type | possible_keys        | key         | key_len | ref         | rows | Extra     | 
+----+-------------+-------+-------+-------------------------------------------+-------------------------------------+---------+---------------------------------------+------+--------------------------+ 
| 1 | SIMPLE  | p  | index | PRIMARY,products_id      | products_id       | 5  | NULL         | 4539 | Using where; Using index | 
| 1 | SIMPLE  | p2c | ref | PRIMARY         | PRIMARY        | 4  | kikleding.p.products_id    | 1 | Using where; Using index | 
| 1 | SIMPLE  | ps15 | ref | products_id        | products_id       | 12  | kikleding.p2c.products_id,const,const | 1 | Using where    | 
| 1 | SIMPLE  | ps10 | ref | products_id        | products_id       | 12  | kikleding.p.products_id,const,const | 1 | Using where    | 
| 1 | SIMPLE  | pa | ref | idx_products_attributes_products_id  | idx_products_attributes_products_id | 4  | kikleding.p.products_id    | 6 |       | 
| 1 | SIMPLE  | pv | ref | PRIMARY         | PRIMARY        | 4  | kikleding.pa.options_values_id  | 2 | Using where    | 
| 1 | SIMPLE  | ps | ref | idx_products_stock_attributes,products_id | idx_products_stock_attributes  | 4  | kikleding.ps15.products_id   | 6 | Using where    | 
+----+-------------+-------+-------+-------------------------------------------+-------------------------------------+---------+---------------------------------------+------+--------------------------+ 

我試圖指數大部分表,裁判仍然給前的第一排NULL平原。

它現在輸出7列,有時我需要輸出50列。

有什麼建議嗎?

+0

什麼是'products_options_values_names'?它屬於「產品」表嗎?如果是,它可能是一個選項來標準化您的數據模型,因此優化器可以使用外鍵。 – ErnestV

+0

它包含在product_options_values表中 –

+0

什麼是您的服務器的硬件規格,並且您確定您的緩衝區足夠大? (查詢很簡單,並且計算7 x 4k行不應該花很長的時間)。 – RandomSeed

回答

3

ref = NULL僅意味着來自p表(即product)的行不與其他行相連。這些行是您的查詢中第一個被選中的行,並且來自其他表的行將被重新連接。我總是期望EXPLAIN的第一行顯示ref = NULL

基本上,你的執行計劃說:從products

  1. 提取行匹配WHERE條件
  2. 然後提取行從(1)在products.products_id
  3. products_to_categories匹配的行等了所有表

建議的附加索引:

  • 表(列)
  • 產品(產品,products_status)
  • products_specifications(products_id,規格,LANGUAGE_ID,specifications_id)
  • products_to_categories(products_id,categories_id)

第一一個人應該明智地幫助,我不會對其他兩個人有太多的期待。

我認爲問題在於你的很多COUNT(IF())。這是駭人聽聞的,引擎並沒有真正針對這種查詢進行優化。相反,你的目標必須是返回結果集是這樣的:

 

+---------------+-------+ 
| specification | count | 
+---------------+-------+ 
| All Season |  1 | 
+---------------+-------+ 
| Winter  | 289 | 
+---------------+-------+ 
| ...   | ... | 
+---------------+-------+ 

您的查詢應該是這樣的:

SELECT 
    specification, 
    COUNT(*) 
FROM products 
JOIN ... -- your current JOIN list 
GROUP BY specification -- this is the important bit 

...,應該是幾乎瞬間,即使沒有額外的索引(或者products_specifications(products_id, specification)

+0

感謝您的意見,我已將您的建議編入索引。在4546行中只有7行的status = 0,我認爲Mysql決定不使用這個索引。 也是規範,計數查詢沒有多大幫助。 1.07秒對1.06秒 –

+0

請注意,通過「'products(product_id,products_status)''我是指'product_id' **和**'products_status'上的複合索引(兩列索引)(與兩個單獨索引)。我不認爲存在這樣的索引(您的索引稱爲「products_status」,這表明索引的第一列是「product_status」)。嘗試'ALTER TABLE產品ADD INDEX pid_pstatus(product_id,product_status)'然後再次檢查您的執行計劃。但是,如果大多數產品都有'product_status = 1',那麼這肯定是無用的。 – RandomSeed

+0

對具有GROUP BY的版本的相同備註:首先在'products_specifications(products_id,specification)'上添加一個複合索引。 – RandomSeed