【问题标题】:MySQL how to optimize query with bunch of subqueriesMySQL如何使用一堆子查询优化查询
【发布时间】:2017-07-20 08:13:30
【问题描述】:

我有一个庞大的项目需要进行统计。这个查询给了我准确的结果,但加载速度有点慢,需要以某种方式优化它,但不知道如何。

SELECT
    TRIM(`op`.`products_quantity`) AS `products_quantity`,
    TRIM(`op`.`products_price`) AS `products_price`,
    TRIM(`op`.`orders_products_status`) AS `orders_products_status`,
    TRIM(`p`.`product_type`) AS `product_type`,
    IF(`p`.`product_type` IN ('G'),FLOOR(`op`.`final_price`*`op`.`products_quantity`),
        `op`.`final_price`) AS `final_price`,
    TRIM((
        SELECT
            `o`.`payment_method`
        FROM
            `orders` `o`
        WHERE
            `o`.`orders_id` = `op`.`orders_id`
        GROUP BY `o`.`orders_id`
    )) AS `payment_method`,
    IF(
        TRIM(DATE_FORMAT(STR_TO_DATE(`cd`.`concert_date`,'%d/%m/%Y'),'%d/%m/%Y')) LIKE (
            SELECT  
                TRIM(DATE_FORMAT(`o`.`date_purchased`,'%d/%m/%Y'))
            FROM
                `orders` `o`
            WHERE
                `o`.`orders_id` = `op`.`orders_id`
            GROUP BY `o`.`orders_id`
        ),
        1,0
    ) AS `same_day`
FROM
    `categories` `c`,
    `categories_description` `cd`,
    `products` `p`,
    `orders_products` `op`
WHERE
    `c`.`section_id` = 25
AND
    `cd`.`categories_id` = `c`.`categories_id`
AND
    `p`.`section_id` = `c`.`section_id`
AND
    `p`.`product_type` IN ('P')
AND
    `op`.`products_id` = `p`.`products_id`
GROUP BY `op`.`orders_products_id`
ORDER BY `payment_method` ASC

有人有什么建议吗?

我还想从 SQL 专家那里得到一些很好的解释,如何组织类似查询的最佳方式以及在 WHERE 部分中首先需要的是什么。

【问题讨论】:

  • 为什么这个问题被标记为php
  • EXPLAIN 是你的朋友
  • 如果您将尝试获取的记录中的table structuresbrief description 添加为查询的输出,您将获得更多有用的答案。

标签: php mysql sql


【解决方案1】:

您可以通过使用 JION

加入所有表来更好地做到这一点

试试这样:-

SELECT
        TRIM(`op`.`products_quantity`) AS `products_quantity`,
        TRIM(`op`.`products_price`) AS `products_price`,
        TRIM(`op`.`orders_products_status`) AS `orders_products_status`,
        TRIM(`p`.`product_type`) AS `product_type`,
        IF(`p`.`product_type` IN ('G'),FLOOR(`op`.`final_price`*`op`.`products_quantity`),
            `op`.`final_price`) AS `final_price`,
        TRIM((
            SELECT
                `o`.`payment_method`
            FROM
                `orders` `o`
            WHERE
                `o`.`orders_id` = `op`.`orders_id`
            GROUP BY `o`.`orders_id`
        )) AS `payment_method`,
        IF(
            TRIM(DATE_FORMAT(STR_TO_DATE(`cd`.`concert_date`,'%d/%m/%Y'),'%d/%m/%Y')) LIKE (
                SELECT  
                    TRIM(DATE_FORMAT(`o`.`date_purchased`,'%d/%m/%Y'))
                FROM
                    `orders` `o`
                WHERE
                    `o`.`orders_id` = `op`.`orders_id`
                GROUP BY `o`.`orders_id`
            ),
            1,0
        ) AS `same_day`
    FROM
        `categories` `c`
        join `categories_description` `cd` on `cd`.`categories_id` = `c`.`categories_id`
        join `products` `p` on `p`.`section_id` = `c`.`section_id`
        join `orders_products` `op` on `op`.`products_id` = `p`.`products_id`
    WHERE
        `c`.`section_id` = 25
    AND
        `p`.`product_type` IN ('P')

    GROUP BY `op`.`orders_products_id`
    ORDER BY `payment_method` ASC

【讨论】:

  • 有点快,但仍然很慢。
  • 一般快 0.010 秒。
【解决方案2】:

您可以尝试运行几个基本步骤:

  • 检查/添加连接列的索引
  • 单独运行较小的查询并首先改进它们。 使用“解释”检查用于返回结果的行数。 尝试减少这个数字。
  • 对更大的查询执行相同的步骤。

【讨论】:

  • 这不是对实际问题的回答,它仅提供一般性提示。也许应该是评论。
  • 这是对一般问题的一般回答 :) 我们手头没有数据库模式 :)
【解决方案3】:

由于没有数据,我无法验证查询。但我认为以下可选查询可能会有所帮助:

SELECT
    TRIM(`op`.`products_quantity`) AS `products_quantity`,
    TRIM(`op`.`products_price`) AS `products_price`,
    TRIM(`op`.`orders_products_status`) AS `orders_products_status`,
    TRIM(`p`.`product_type`) AS `product_type`,
    IF(`p`.`product_type` = 'G', FLOOR(`op`.`final_price` * `op`.`products_quantity`), `op`.`final_price`) AS `final_price`,
    TRIM(`t`.`payment_method`) AS `payment_method`,
    IF( TRIM(DATE_FORMAT(STR_TO_DATE(`cd`.`concert_date`,'%d/%m/%Y'),'%d/%m/%Y')) LIKE 
        TRIM(DATE_FORMAT(`t`.`date_purchased`,'%d/%m/%Y')), 1, 0 ) AS `same_day`
FROM
    `categories` `c` INNER JOIN `categories_description` `cd` ON `c`.`categories_id` = `cd`.`categories_id`
    INNER JOIN `products` `p` ON `c`.`section_id` = `p`.`section_id`
    INNER JOIN `orders_products` `op` ON `p`.`products_id` = `op`.`products_id`
    INNER JOIN
    ( SELECT `o`.`orders_id`, `o`.`payment_method`, 
       TRIM(DATE_FORMAT(`o`.`date_purchased`,'%d/%m/%Y')) AS `date_purchased`
       FROM `orders` `o` GROUP BY `o`.`orders_id` ) AS `t` ON `op`.`orders_id` = `t`.`orders_id`
WHERE `c`.`section_id` = 25 AND `p`.`product_type` IN ('P')
GROUP BY `op`.`orders_products_id`
ORDER BY `payment_method`;

请注意,以下部分对于两个内部子查询是通用的:

FROM `orders` `o`
WHERE `o`.`orders_id` = `op`.`orders_id`
GROUP BY `o`.`orders_id`

这意味着您以相同的条件引用同一个表两次,只是为了获得两个不同的列。所以我删除了该部分并将其添加为单个子查询的INNER JOIN

另请注意,IN 的括号中只有一个值。所以我用=替换了IN

如果这对您有帮助,请告诉我。

【讨论】:

  • 你是对的,几乎可以工作了,只是same_day 没有正确显示数据。感谢原则
  • 当然。如果您发布表结构和一些示例数据,我们可能会弄清楚。
猜你喜欢
  • 2014-07-31
  • 2014-03-26
  • 1970-01-01
  • 2011-11-27
  • 2021-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-11
相关资源
最近更新 更多