2013-10-18 87 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