优化MySQL查询

时间:2015-01-30 10:14:21

标签: mysql left-join

我有一个查询,相对较慢。我试图多次重写它,但我找不到更好的解决方案。所以我想问你,如果它从一开始就以错误的方式写成,那就没问题。

    SELECT sql_calc_found_rows 
    present_id, present_id, present_url, present_name, present_text_short, foto_name, price_id, price_price, price_amount, price_dis 
    FROM a_present 
    LEFT JOIN 
       (SELECT price_id, price_present_id, price_supplier_id, price_dis, price_amount, 
        (CASE WHEN price_dis <> 0 THEN price_dis ELSE price_amount END) as price_price 
       FROM a_price 
       WHERE 
       price_visibility = 1 AND price_deleted <> 1 
       GROUP BY price_id ) pri 
    ON pri.price_present_id = present_id 
    LEFT JOIN _present_fotos ON foto_id = present_title_foto 
    LEFT JOIN _cate_pres ON cp_present = present_id 
    WHERE present_visibility = 1 AND present_deleted <> 1 AND price_price > 0 AND present_out <> 1 AND cp_category IN (30,31,232,32) 
    GROUP BY present_id 
    ORDER BY price_price 
    LIMIT 8

描述:price_dis是折扣后的价格,price_amount是折扣前的价格..每个产品(现在)的价格都比一个更多..是否有更快的解决方案来选择最终价格?

如果你发现桌面结构不好,我会遇到麻烦:)

非常感谢!

编辑: explain select

1 个答案:

答案 0 :(得分:0)

好的,所以我看到了一些可以改进的事情。

首先,您正在使用从子查询派生的表来加入 - 使用子查询MySQL不使用索引(因此减速)。不要使用子查询加入,而是尝试使用表a_price本身加入,并将CASE语句放在原始(父)SELECT中。它应该允许MySQL在JOINing时使用索引,并且当子查询返回许多行时非常重要。

它应该看起来像这样(包括MIN()GROUP BY,因为您需要最低价格):

SELECT (...), price_amount, price_dis, MIN((CASE WHEN pri.price_dis <> 0 THEN pri.price_dis ELSE pri.price_amount END)) as price_price 
    FROM a_present 
    LEFT JOIN a_price pri 
    ON pri.price_present_id = present_id AND price_visibility = 1 AND price_deleted <> 1 
(...)
GROUP BY present_id

其次 - 如EXPLAIN SELECT所示 - MySQL不使用表_cate_pres上的索引。你应该使用索引加入JOIN并选择你需要的类别(因为你把它们中的一些放在IN (..)语句中)。

尝试在_cate_pres.cp_category上添加索引,和/或在此表上添加复合索引(使用两列 - cp_category和cp_present)。

通常,您希望实现的结果(并非总是可行,但在您的情况下我非常确定),是让{@ 1}}中的以下内容消失:

  • [key] NULL - 这表示此特定集合中没有使用密钥
  • [Extra]使用临时 - 这意味着创建一个临时表来检索结果,这通常对性能不利
  • [Extra]使用filesort - 这意味着没有索引用于排序,因此排序过程很慢。

详细了解indexes in the Mysql docs,请注意EXPLAIN output