具有多个计算的Mysql查询变慢

Posted

技术标签:

【中文标题】具有多个计算的Mysql查询变慢【英文标题】:Mysql query having multiple calculation getting slower 【发布时间】:2013-04-05 06:17:12 【问题描述】:

我有一个用于报告的 mysql 视图。即它计算了一天中有多少 cod 订单、预付订单、cod 订单金额、预付订单金额、总计和更多计算,并且它连接了 5 个表。它变得太慢了。 除了使用视图之外,有没有更好的方法来满足这种要求。或者如何让这样的需求更快

SELECT
  DATE_FORMAT(`orders`.`placed_date`,'%Y-%m%-%d 00:00:00') AS `orderdate`,
  DATE_FORMAT(`orders`.`placed_date`,'%Y-%m%-%d') AS `orderdt`,
  COUNT(DISTINCT `orders`.`order_id`) AS `orderscount`,
  SUM(`order_item`.`quantity`) AS `qunty`,
  SUM((`order_item`.`quantity` * `order_item`.`a_unitprice`)) AS `price`,
  COUNT(DISTINCT (CASE `payment_type`.`a_name` WHEN 'COD' THEN `orders`.`order_id` END)) AS `codorderscount`,
  COUNT(DISTINCT (CASE `payment_type`.`a_name` WHEN 'Prepaid' THEN `orders`.`order_id` END)) AS `prepaidorderscount`,
  ROUND(SUM(IF((`payment_type`.`a_name` = 'COD'),ROUND((((((`order_item`.`quantity` * `order_item`.`a_unitprice`) - IFNULL(ABS(`getdisc_function`(`order_item`.`order_item_id`,`order_item`.`quantity`)),0)) + IFNULL(`getgiftwrap_amount_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)) + IFNULL(`order_item`.`sales_tax`,0)) + IFNULL(`getshipping_charge_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)),2),0)),0) AS `cod`,
  ROUND(SUM(IF((`payment_type`.`a_name` = 'Prepaid'),ROUND((((((`order_item`.`quantity` * `order_item`.`a_unitprice`) - IFNULL(ABS(`getdisc_function`(`order_item`.`order_item_id`,`order_item`.`quantity`)),0)) + IFNULL(`getgiftwrap_amount_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)) + IFNULL(`order_item`.`sales_tax`,0)) + IFNULL(`getshipping_charge_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)),2),0)),0) AS `Prepaid`,
  ROUND((SUM(IF((`payment_type`.`a_name` = 'COD'),ROUND((((((`order_item`.`quantity` * `order_item`.`a_unitprice`) - IFNULL(ABS(`getdisc_function`(`order_item`.`order_item_id`,`order_item`.`quantity`)),0)) + IFNULL(`getgiftwrap_amount_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)) + IFNULL(`order_item`.`sales_tax`,0)) + IFNULL(`getshipping_charge_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)),2),0)) + SUM(IF((`payment_type`.`a_name` = 'Prepaid'),ROUND((((((`order_item`.`quantity` * `order_item`.`a_unitprice`) - IFNULL(ABS(`getdisc_function`(`order_item`.`order_item_id`,`order_item`.`quantity`)),0)) + IFNULL(`getgiftwrap_amount_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)) + IFNULL(`order_item`.`sales_tax`,0)) + IFNULL(`getshipping_charge_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)),2),0))),0) AS `grandtotal`,
  ROUND((ROUND((SUM(IF((`payment_type`.`a_name` = 'COD'),ROUND((((((`order_item`.`quantity` * `order_item`.`a_unitprice`) - IFNULL(ABS(`getdisc_function`(`order_item`.`order_item_id`,`order_item`.`quantity`)),0)) + IFNULL(`getgiftwrap_amount_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)) + IFNULL(`order_item`.`sales_tax`,0)) + IFNULL(`getshipping_charge_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)),2),0)) + SUM(IF((`payment_type`.`a_name` = 'Prepaid'),ROUND((((((`order_item`.`quantity` * `order_item`.`a_unitprice`) - IFNULL(ABS(`getdisc_function`(`order_item`.`order_item_id`,`order_item`.`quantity`)),0)) + IFNULL(`getgiftwrap_amount_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)) + IFNULL(`order_item`.`sales_tax`,0)) + IFNULL(`getshipping_charge_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)),2),0))),0) / COUNT(DISTINCT `orders`.`order_id`)),0) AS `avgtickectsize`,
  ROUND((ROUND((SUM(IF((`payment_type`.`a_name` = 'COD'),ROUND((((((`order_item`.`quantity` * `order_item`.`a_unitprice`) - IFNULL(ABS(`getdisc_function`(`order_item`.`order_item_id`,`order_item`.`quantity`)),0)) + IFNULL(`getgiftwrap_amount_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)) + IFNULL(`order_item`.`sales_tax`,0)) + IFNULL(`getshipping_charge_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)),2),0)) + SUM(IF((`payment_type`.`a_name` = 'Prepaid'),ROUND((((((`order_item`.`quantity` * `order_item`.`a_unitprice`) - IFNULL(ABS(`getdisc_function`(`order_item`.`order_item_id`,`order_item`.`quantity`)),0)) + IFNULL(`getgiftwrap_amount_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)) + IFNULL(`order_item`.`sales_tax`,0)) + IFNULL(`getshipping_charge_function`(`order_item`.`order_item_id`,`order_item`.`quantity`),0)),2),0))),0) / SUM(`order_item`.`quantity`)),0) AS `avgitemprice`,
  ROUND((SUM(`order_item`.`quantity`) / COUNT(DISTINCT `orders`.`order_id`)),0) AS `avgitemperorder`,
  COUNT(DISTINCT (CASE `status`.`status_code` WHEN 'S' THEN `orders`.`order_id` WHEN 'DE' THEN `orders`.`order_id` END)) AS `dispached`,
  (COUNT(DISTINCT `orders`.`order_id`) - COUNT(DISTINCT (CASE `status`.`status_code` WHEN 'S' THEN `orders`.`order_id` WHEN 'DE' THEN `orders`.`order_id` END))) AS `notdispached`
FROM (((((`orders`
       JOIN `order_item`
         ON ((`order_item`.`order_id` = `orders`.`order_id`)))
      JOIN `payment_instruction`
        ON ((`payment_instruction`.`order_id` = `orders`.`order_id`)))
     JOIN `subpayment_type`
       ON ((`payment_instruction`.`payment_method` = `subpayment_type`.`subpayment_type_id`)))
    JOIN `payment_type`
      ON (((`payment_type`.`payment_type_id` = `subpayment_type`.`payment_type_id`)
           AND (`payment_type`.`a_name` = ('Prepaid'
                                             OR 'COD')))))
   LEFT JOIN `status`
     ON ((`status`.`a_statusid` = `orders`.`orderstatus_id`)))
WHERE (`status`.`status_code` NOT IN('PP','PE','X'))
GROUP BY DATE_FORMAT(`orders`.`placed_date`,'%y-%m%-%d')

【问题讨论】:

请发布您的查询并解释... @Meherzad - 现在检查。 请同时添加 EXPLAIN 语句的结果:EXPLAIN SELECT ...,以便我们知道 MySQL 正在使用哪些索引以及它需要处理多少行 【参考方案1】:

只有查询(没有 DDL、行数等)这是相当猜测。

您可以尝试在用于连接表的列和WHERE 子句中添加索引。如果这些表中有很多行,这尤其有意义。

还要尝试识别此语句中最慢的部分。也许是 JOIN,也许是 SELECT 列表中的这些计算?你可以剪掉一部分,看看没有它会不会很快。那么你应该专注于这个最慢的部分。

【讨论】:

我已经做到了。如果我删除所有计算并用 * 代替它,它会非常非常快。计算是这里的主要内容,这里是重复计算。如果我进行一次计算并存储在某个变量中,它会很有帮助。但做不到。【参考方案2】:

MySQL 中的视图可能很慢。有一篇关于这个问题的文章-MySQL VIEW as performance troublemaker。

如果可能 - 使用没有视图的简单 SELECT 查询。

【讨论】:

以上是关于具有多个计算的Mysql查询变慢的主要内容,如果未能解决你的问题,请参考以下文章

一个最令人费解的 MySQL 问题:查询偶尔变慢

mysql加了性别变慢

使用 group by 聚合计数 > 100 万用户 的 Mysql 查询性能变慢

为啥 MySQL 查询在使用 LIMIT 和 Order BY 时会变慢?

mysql (python) AWS 查询堆积导致速度变慢

我的应用程序中的哪些文件使 Mysql 查询日志条目变慢