【问题标题】:Slow performance of combined fast MySQL queries组合快速 MySQL 查询的性能缓慢
【发布时间】:2016-01-23 20:57:17
【问题描述】:

我有 2 个查询在单独运行时运行得非常快,但是当将其中一个用作子查询时,性能会急剧下降。

快速查询 I:

SELECT DISTINCT p.products_image, 
                p.products_subimage1, 
                pd.products_name, 
                p.products_quantity, 
                p.products_model, 
                p.products_ordered, 
                p.products_id, 
                p.products_price, 
                p.products_weight, 
                p.products_length, 
                p.products_width, 
                p.products_height, 
                p.products_tax_class_id, 
                p.products_status, 
                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 
FROM   products p 
       LEFT JOIN specials s 
              ON p.products_id = s.products_id 
       LEFT JOIN products_to_categories p2c 
              ON p.products_id = p2c.products_id 
       LEFT JOIN products_description pd 
              ON p.products_id = pd.products_id 

       LEFT JOIN products_attributes pa 
              ON p.products_id = pa.products_id
       LEFT JOIN (SELECT `products_id`, 
               `products_stock_attributes`, 
               `products_stock_quantity` 
        FROM   products_stock 
        WHERE  `products_stock_quantity` > 0) t 
       ON t.products_id = p.products_id 
       WHERE t.products_stock_attributes IN ( '1-31', '1-25', '1-18', '1-7' ) 
       AND p.products_status = '1' 
       AND Date_sub(Curdate(), INTERVAL 30 day) >= p.products_date_added 
       AND pa.options_values_id IN ( 31, 25, 18, 7 ) 
GROUP  BY p.products_id 
HAVING Count(DISTINCT pa.options_values_id) = 4 
       AND Count(DISTINCT t.products_stock_attributes) = 4 

快速查询 II:

SELECT sul2.* 
FROM   stock_update_log sul2 
INNER JOIN (SELECT products_id, 
     Max(date_time) AS maxDateTime 
FROM   stock_update_log 
WHERE  stock_qty_change > 1 
AND id > 154700 
   AND Date_sub(Curdate(), INTERVAL 360 day)<= From_unixtime(date_time) 
GROUP  BY products_id)gsul 
       ON sul2.products_id = gsul.products_id 
AND sul2.date_time = gsul.maxdatetime

组合查询(非常慢):

SELECT DISTINCT p.products_image, 
                p.products_subimage1, 
                pd.products_name, 
                p.products_quantity, 
                p.products_model, 
                p.products_ordered, 
                p.products_id, 
                p.products_price, 
                sul.date_time, 
                p.products_weight, 
                p.products_length, 
                p.products_width, 
                p.products_height, 
                p.products_tax_class_id, 
                p.products_status, 
                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 
FROM   products p 
       LEFT JOIN specials s 
              ON p.products_id = s.products_id 
       LEFT JOIN products_to_categories p2c 
              ON p.products_id = p2c.products_id 
       LEFT JOIN products_description pd 
              ON p.products_id = pd.products_id 
       LEFT JOIN (SELECT sul2.* 
                  FROM   stock_update_log sul2 
                         INNER JOIN (SELECT products_id, 
                                            Max(date_time) AS maxDateTime 
                                     FROM   stock_update_log 
                                     WHERE  stock_qty_change > 1 
                                            AND id > 154700 
                                            AND Date_sub(Curdate(), 
                                                INTERVAL 360 day) 
                                                <= 
                                                From_unixtime(date_time) 
                                     GROUP  BY products_id)gsul 
                                 ON sul2.products_id = gsul.products_id 
                                    AND sul2.date_time = gsul.maxdatetime) sul 
              ON p.products_id = sul.products_id 
       LEFT JOIN products_attributes pa 
              ON p.products_id = pa.products_id
       LEFT JOIN (SELECT `products_id`, 
               `products_stock_attributes`, 
               `products_stock_quantity` 
        FROM   products_stock 
        WHERE  `products_stock_quantity` > 0) t 
       ON t.products_id = p.products_id 
       WHERE t.products_stock_attributes IN ( '1-31', '1-25', '1-18', '1-7' ) 
       AND p.products_status = '1' 
       AND Date_sub(Curdate(), INTERVAL 360 day) <= From_unixtime(sul.date_time) 
       AND Date_sub(Curdate(), INTERVAL 30 day) >= p.products_date_added 
       AND sul.id > 154700 
       AND sul.stock_qty_change > 1 
       AND pa.options_values_id IN ( 31, 25, 18, 7 ) 
GROUP  BY p.products_id 
HAVING Count(DISTINCT pa.options_values_id) = 4 
       AND Count(DISTINCT t.products_stock_attributes) = 4 
ORDER  BY sul.date_time DESC 

组合查询结果的解释:

我已经尝试了几个小时来弄清楚为什么以这种方式组合它们时会变得如此缓慢,并试图重写组合查询但无济于事,所以我在这里向专家寻求帮助。

它变得如此缓慢的原因是什么,我应该怎么做才能让它变快?

【问题讨论】:

    标签: mysql performance


    【解决方案1】:

    查询 II 感觉像是有一百万行;生成的 tmp 表没有索引;它隐藏在LEFT JOIN 后面。优化器似乎仍然足够聪明,可以从混乱开始并为联合查询提供 7904 行。

    你能避开LEFT吗?

    然后代码继续执行,但最终必须对照表扫描中的 18057 行检查所有这些行。优化器再次通过使用“连接缓冲区”做了一件聪明的事。尽管如此,7904*923*18057 还是有很多行需要查看。

    这似乎是邪恶的部分:

       LEFT JOIN
         ( SELECT `products_id`, 
                  `products_stock_attributes`, 
                  `products_stock_quantity` 
            FROM    products_stock 
            WHERE  `products_stock_quantity` > 0
        ) t 
       ON t.products_id = p.products_id 
    
       WHERE t.products_stock_attributes IN ( '1-31', '1-25', '1-18', '1-7' ) 
    

    所有这些似乎都是危险信号:

    • 不必要的(?)LEFT;
    • “where attributes in...”在子查询之外,什么时候可以在里面;
    • 您可以将HAVING Count(DISTINCT t.products_stock_attributes) = 4 折叠到子查询中。

    【讨论】:

    • 是的,将WHERE t.products_stock_attributes INHAVING Count(DISTINCT t.products_stock_attributes) = 4 移到这个子查询中解决了这个问题。非常感谢!! :)
    【解决方案2】:

    您正在对 7 个表进行连接,这肯定会非常慢。我建议避免加入超过 3 张桌子。

    你有没有试过自己做这两个查询,然后合并它们的结果?

    【讨论】:

    • 为试图帮助我而点赞。谢谢你。 :)
    猜你喜欢
    • 2016-05-10
    • 2016-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    相关资源
    最近更新 更多