组合MySQL查询的性能降低

时间:2016-02-01 19:01:10

标签: mysql performance

我有多个子查询的查询,运行速度很慢。

SELECT DISTINCT pav.products_options_values_id, 
                pav.products_options_values_name, 
                pav.products_options_values_sort_order 
FROM            products_stock ps, 
                products_options_values pav, 
                ( 
                                SELECT DISTINCT pa.products_id, 
                                                pov.products_options_values_id, 
                                                pov.products_options_values_name, 
                                                pa.options_values_price, 
                                                pa.price_prefix 
                                FROM            products_attributes pa, 
                                                products_options_values pov, 
                                                ( 
                                                                SELECT DISTINCT p.products_image,
                                                                                p.products_quantity,
                                                                                p.products_status,
                                                                                m.manufacturers_id,
                                                                                p.products_id,
                                                                                p.products_date_added,
                                                                                p.products_subimage1,
                                                                                pd.products_name,
                                                                                p.products_price,
                                                                                p.products_length,
                                                                                p.products_width,
                                                                                p.products_height,
                                                                                p.products_tax_class_id,IF(s.status, s.specials_new_products_price, NULL)             AS specials_new_products_price,
                                                                                IF(s.status, s.specials_new_products_price, p.products_price)                         AS final_price,
                                                                                IF(p.clearance_price < p.products_cost*2.25, p.clearance_price, p.products_cost*2.25) AS sorting_price
                                                                FROM            products p 
                                                                LEFT JOIN       manufacturers m
                                                                using          (manufacturers_id)
                                                                LEFT JOIN       specials s 
                                                                ON              p.products_id = s.products_id
                                                                LEFT JOIN       products_attributes pa
                                                                ON              p.products_id = pa.products_id
                                                                LEFT JOIN       products_options po
                                                                ON              pa.options_id = po.products_options_id
                                                                LEFT JOIN       products_options_values pov
                                                                ON              pa.options_values_id = pov.products_options_values_id ,
                                                                                products_description pd,
                                                                                categories c,
                                                                                products_to_categories p2c
                                                                WHERE           p.products_status = '1'
                                                                AND             p.products_id = pd.products_id
                                                                AND             pd.language_id = '1'
                                                                AND             p.products_id = p2c.products_id
                                                                AND             p2c.categories_id = c.categories_id
                                                                AND             (( 
                                                                                                                pd.products_name LIKE '%a%'
                                                                                                OR              po.products_options_name LIKE '%a%'
                                                                                                OR              pov.products_options_values_name LIKE '%a%'
                                                                                                OR              pd.products_description LIKE '%a%') )
                                                                ORDER BY        p.products_id DESC) m
                                WHERE           m.products_id = pa.products_id 
                                AND             pa.options_id = 1
                                AND             pa.options_values_id = pov.products_options_values_id
                                AND             pov.language_id = '1' 
                                GROUP BY        pov.products_options_values_id 
                                ORDER BY        pov.products_options_values_sort_order ASC) q
WHERE           q.products_id = ps.products_id 
AND             ps.products_stock_attributes = concat('1-', pav.products_options_values_id) 
AND             ps.products_stock_quantity > 0 
ORDER BY        pav.products_options_values_sort_order ASC

这是EXPLAIN结果: http://grabilla.com/06201-5ce9af70-1837-4bf4-b42e-1ecdda39b3b9.png

尝试优化它几个小时,但我可能误读了EXPLAIN信息,因为无论我做什么,它似乎都不会让它更快,所以我在这里寻求专家的帮助。

导致它变得如此缓慢的原因是什么?我应该怎样做才能使它变得快速?

1 个答案:

答案 0 :(得分:1)

首先,我使用一致的JOIN子句与逗号列出的表清理查询。接下来,您最内部的查询有一个顺序,显然没有被用于任何好处。如果无法优化,则排序依据会导致查询出现大的延迟。

SELECT DISTINCT 
      pav.products_options_values_id,
      pav.products_options_values_name,
      pav.products_options_values_sort_order
   FROM
      products_stock ps
         JOIN products_options_values pav
            ON ps.products_stock_attributes = concat('1-', pav.products_options_values_id) 
            AND ps.products_stock_quantity > 0 
         JOIN ( SELECT DISTINCT 
                      pa.products_id, 
                      pov.products_options_values_id, 
                      pov.products_options_values_name, 
                      pa.options_values_price, 
                      pa.price_prefix 
                   FROM
                      products_attributes pa
                         JOIN products_options_values pov
                            ON pa.options_values_id = pov.products_options_values_id
                            AND pov.language_id = '1' 
                         JOIN ( SELECT DISTINCT 
                                      p.products_image,
                                      p.products_quantity,
                                      p.products_status,
                                      p.manufacturers_id,
                                      p.products_id,
                                      p.products_date_added,
                                      p.products_subimage1,
                                      pd.products_name,
                                      p.products_price,
                                      p.products_length,
                                      p.products_width,
                                      p.products_height,
                                      p.products_tax_class_id,
                                      IF(s.status, s.specials_new_products_price, NULL ) 
                                         AS specials_new_products_price,
                                      IF(s.status, s.specials_new_products_price, p.products_price )
                                         AS final_price,
                                      IF( p.clearance_price < p.products_cost * 2.25, p.clearance_price, p.products_cost * 2.25 ) 
                                         AS sorting_price
                                   FROM
                                      products p 
                                         JOIN products_description pd
                                            ON p.products_id = pd.products_id
                                            AND pd.language_id = '1'

THIS SECTION CAN BE REMOVED              JOIN products_to_categories p2c
                                            AND p.products_id = p2c.products_id
                                            JOIN categories c
                                               ON p2c.categories_id = c.categories_id
                                         LEFT JOIN manufacturers m
UP TO THIS LINE                              ON P.manufacturers_id = m.manufacturers_id

                                         LEFT JOIN specials s 
                                            ON p.products_id = s.products_id
                                         LEFT JOIN products_attributes pa
                                            ON p.products_id = pa.products_id
                                            LEFT JOIN products_options po
                                               ON pa.options_id = po.products_options_id
                                            LEFT JOIN products_options_values pov
                                               ON pa.options_values_id = pov.products_options_values_id,
                                   WHERE
                                          p.products_status = '1'
                                      AND (    pd.products_name LIKE '%a%'
                                            OR pd.products_description LIKE '%a%'
                                            OR po.products_options_name LIKE '%a%'
                                            OR pov.products_options_values_name LIKE '%a%' )
                                   ORDER BY
                                      p.products_id DESC) m 
                   WHERE
                          pa.products_id = m.products_id
                      AND pa.options_id = 1
                   GROUP BY
                      pov.products_options_values_id 
                   ORDER BY
                      pov.products_options_values_sort_order ASC) q
            ON ps.products_id = q.products_id 
   ORDER BY
      pav.products_options_values_sort_order ASC

您有类别表的连接,但没有提取任何值或其他条件来返回列。因此我没有必要删除了。随着那个消失了,我接着看了你的Products_To_Categories表,除了在其他任何地方没有使用的额外连接因此被删除之外,它在查询中也没有影响。制造商表也不是必需的,因为你得到的只是制造商的ID,它存在于产品表中,因此不需要另外的表

现在开始索引。我会查看表的以下索引

table                   index
products                ( products_status, products_id )
products_description    ( products_id, language_id )
products_to_categories  ( products_id, categories_id ) 
categories              ( categories_id )
manufacturers           ( manufacturers_id )
specials                ( products_id, status, specials_new_products_price )
products_attributes     ( products_id, options_id, options_values_id )
products_options        ( products_options_id, products_options_name )
products_options_values ( products_options_values_id, products_options_values_name )

这只是评论的第一步。现在我想再花一步来删除一层嵌套查询。您的INNER-MOST查询会加入&#34; products_options_values&#34;但仅适用于Language ID = 1.为什么不将该列标准添加到内部查询中。然后将pov.products_options_values_id和pov.products_options_values_name列添加到内部查询和内部查询的语言ID,您不需要再次重新加入它们。它们可以通过&#34; m。&#34;最内层查询的别名。 vs the rejoin。

类似地,您的最内部查询对products_attributes进行LEFT JOIN,但在&#34; m&#34;之外。别名查询结果仅应用options_id = 1的WHERE子句。这没有意义。为什么不直接添加到最内层的查询。如果你只是在寻找语言ID = 1或者Options_ID = 1之类的东西,那么消除额外的水平可能会有很大帮助,因为你正在限制所有记录的拉动。

同样,这个格式化的查询与您的上下文相同,只是结构略有不同,缩短了缩进,以便更好地查看上下文和嵌套需求。

来自聊天的反馈

select 
      PQ.*
   from
    ( SELECT STRAIGHT_JOIN DISTINCT 
          p.products_id, 
          p.products_image, 
          p.products_quantity, 
          p.products_status, 
          p.manufacturers_id, 
          p.products_date_added, 
          p.products_subimage1, 
          pd.products_name, 
          p.products_price, 
          p.products_length, 
          p.products_width, 
          p.products_height, 
          pov.products_options_values_id, 
          pov.products_options_values_name, 
          pov.language_id, 
          pov.products_options_values_sort_order, 
          p.products_tax_class_id,
          IF(s.status, s.specials_new_products_price, NULL) 
             AS specials_new_products_price, 
          IF(s.status, s.specials_new_products_price, p.products_price) 
             AS final_price, 
          IF(p.clearance_price < p.products_cost*2.25, p.clearance_price, p.products_cost*2.25) 
             AS sorting_price 
       FROM 
          products_attributes pa 
             JOIN products_options_values pov 
                ON pa.options_values_id = pov.products_options_values_id
                AND pov.language_id = '1' 
                LEFT JOIN products_options po 
                   ON pa.options_id = po.products_options_id 
             JOIN products p 
                ON pa.products_id = p.products_id
                AND p.products_status = '1' 
                JOIN products_description pd
                   ON p.products_id = pd.products_id 
                   AND pd.language_id = '1' 
                JOIN products_to_categories p2c 
                   ON p.products_id = p2c.products_id 
                   JOIN categories c
                      ON p2c.categories_id = c.categories_id 
                LEFT JOIN manufacturers m 
                   using (manufacturers_id) 
                LEFT JOIN specials s 
                   ON p.products_id = s.products_id 
       WHERE 
              pa.options_id = '1' 
          AND (  pd.products_name LIKE '%a%' 
              OR po.products_options_name LIKE '%a%' 
              OR pov.products_options_values_name LIKE '%a%' 
              OR pd.products_description LIKE '%a%'))  PQ
   order by 
      PQ.Products_id

另外,请注意,我删除了最终的&#34; Order by&#34;条款