【问题标题】:Optimize joined order by query通过查询优化连接顺序
【发布时间】:2013-05-26 05:47:10
【问题描述】:

我有以下疑问:

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 使用临时;使用文件排序 1 PRIMARY p_products eq_ref PRIMARY PRIMARY 4 pdev.p_product_p_category.p_product_id 1 使用 where 1 主要 全部 NULL NULL NULL NULL 78 2 DERIVED p_orderedproducts 索引 order_date p_product_id 4 NULL 201 使用 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 使用where;使用索引;使用临时的;使用文件排序 1 SIMPLE p_products eq_ref PRIMARY PRIMARY 4 pdev.p_product_p_category.p_product_id 1 使用 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 使用临时;使用文件排序 1 PRIMARY nr1media_products eq_ref PRIMARY PRIMARY 4 cat.nr1media_product_id 1 使用 where 2 DERIVED nr1media_product_nr1media_category range nr1media_category_id nr1media_category_id 4 NULL 62066 使用 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

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

我想我需要为orderedproducts 连接找到另一个解决方案,它仍然会将查询速度减慢到> 1 秒。可能会做一个 cron 来更新每晚一次售出的产品的排名,并将该信息保存到 p_products 表中。

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

【问题讨论】:

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


    【解决方案1】:

    您正在将每种类型的类别加入产品 - 只有这样它才会按类别 id 过滤

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

    INNER JOIN `p_product_p_category`
    

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

    这样您就可以从一开始就致力于较小的产品子集

    【讨论】:

    • 使用子查询的执行时间实际上更长,我会根据你的建议用解释更新帖子。
    【解决方案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
    

    【讨论】:

    • 感谢 Thomas,帮助节省了一些时间!仍然不是我想要的,所以我现在也要执行 Ochi 的建议。
    猜你喜欢
    • 1970-01-01
    • 2013-09-27
    • 2016-11-01
    • 2022-11-30
    • 2020-07-24
    • 2020-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多