通过查询优化联接订单

时间:2013-05-30 15:10:10

标签: mysql performance group-by sql-order-by left-join

我有以下问题:

SELECT `p_products`.`id`, `p_products`.`name`, `p_products`.`date`, 
       `p_products`.`img`, `p_products`.`safe_name`, `p_products`.`sku`, 
       `p_products`.`productstatusid`, `op`.`quantity`
FROM `p_products` 
INNER JOIN `p_product_p_category` 
        ON `p_products`.`id` = `p_product_p_category`.`p_product_id`
LEFT JOIN (SELECT `p_product_id`,`order_date`,SUM(`product_quantity`) as quantity 
           FROM `p_orderedproducts` 
           WHERE `order_date`>='2013-03-01 16:51:17' 
           GROUP BY `p_product_id`) AS op
       ON `p_products`.`id` = `op`.`p_product_id`
WHERE `p_product_p_category`.`p_category_id` IN ('15','23','32') 
  AND `p_products`.`active` = '1'
GROUP BY `p_products`.`id`
ORDER BY `date` DESC

解释说:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY p_product_p_category    ref p_product_id,p_category_id,p_product_id_2   p_category_id   4   const   8239    Using temporary; Using filesort
1   PRIMARY p_products  eq_ref  PRIMARY PRIMARY 4   pdev.p_product_p_category.p_product_id  1   Using where
1   PRIMARY   ALL NULL    NULL    NULL    NULL    78  
2   DERIVED p_orderedproducts   index   order_date  p_product_id    4   NULL    201 Using where

我在许多列上都有索引,包括p_products.date。

问题是当许多类别中有超过5000种产品时的速度。 60000产品需要> 1秒。有什么方法可以加快速度吗?

如果我删除了左连接,结果是:

,这也适用
id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  p_product_p_category    index   p_product_id,p_category_id,p_product_id_2   p_product_id_2  8   NULL    91167   Using where; Using index; Using temporary; Using filesort
1   SIMPLE  p_products  eq_ref  PRIMARY PRIMARY 4   pdev.p_product_p_category.p_product_id  1   Using where

中间表p_product_p_category在p_product_id和p_category_id上都有索引,以及两者的组合索引。

尝试Ochi的建议并最终得到:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY   ALL NULL    NULL    NULL    NULL    62087   Using temporary; Using filesort
1   PRIMARY nr1media_products   eq_ref  PRIMARY PRIMARY 4   cats.nr1media_product_id    1 Using where
2   DERIVED nr1media_product_nr1media_category  range   nr1media_category_id    nr1media_category_id    4   NULL    62066   Using where

我想我可以简化问题,如何在类别中间表上加入我的产品,以获取所选类别的所有独特产品,按日期排序。

编辑:

这为我提供了类别中所有独特的产品,而不使用临时表进行排序或分组:

SELECT
    `p_products`.`id`,
    `p_products`.`name`,
    `p_products`.`img`,
    `p_products`.`safe_name`,
    `p_products`.`sku`,
    `p_products`.`productstatusid`
FROM
    p_products
WHERE
    EXISTS (
        SELECT
            1
        FROM
            p_product_p_category
        WHERE
            p_product_p_category.p_product_id = p_products.id
        AND p_category_id IN ('15', '23', '32')
    )
AND p_products.active = 1
ORDER BY
    `date` DESC

上面的查询速度非常快,比使用按顺序按(0.04 VS 0.7秒)的连接快得多,虽然我不明白为什么它可以在没有临时表的情况下执行此查询。

我认为我需要为orderedproducts join找到另一个解决方案,它仍然会将查询速度降低到> 1秒。可能会让cron每晚更新一次销售产品的排名,并将该信息保存到p_products表中。

除非有人有明确的解决方案......

2 个答案:

答案 0 :(得分:2)

您要将所有类别的类别加入到产品中 - 然后才会按类别ID

进行过滤

尝试尽快限制您的查询,例如而不是

INNER JOIN `p_product_p_category`

DO

INNER JOIN ( SELECT * FROM `p_product_p_category` WHERE `p_category_id` IN ('15','23','32') )

这样您就可以从开始

开始研究较小的产品子集

答案 1 :(得分:2)

一种可能的解决方案是删除派生表,然后只执行一个Group By:

Select P.id, P.name, P.date
    , P.img, P.safe_name, P.sku
    , P.productstatusid
    , Sum( OP.product_quantity ) As quantity
From p_products As P
    Join p_product_p_category As CAT
        On p_products.id = CAT.p_product_id

    Left Join p_orderedproducts As OP
        On OP.p_product_id = P.id
            And OP.order_date >= '2013-03-01 16:51:17' 

Where CAT.p_category_id In ('15','23','32') 
    And P.active = '1'
Group By P.id, P.name, P.date
    , P.img, P.safe_name, P.sku
    , P.productstatusid
Order By P.date Desc