挤压MySQL SUM + JOINS的速度更快

时间:2013-04-28 17:08:19

标签: mysql sql

我有一个半复杂的JOIN结构,根据订单从我的MySQL数据库中获取特定信息。首先让我给你SQL查询;

SELECT
    #orders.*,
    orders.id,
    customers.lastname,
    customers.priority,
    shipments.status,
    pmv_sl.productmodelvariant_id,
    pmv_sl.nr AS pmv_nr,
    COALESCE(SUM(orderlines.nr), 0) AS orderlines_nr_count,
    COALESCE(SUM(shipment_lines.nr), 0) AS shipment_lines_nr_count
FROM orders
    INNER JOIN  customers       ON customers.id = orders.customer_id
    INNER JOIN  platforms       ON platforms.id = orders.platform_id
    INNER JOIN  stocklocations  ON stocklocations.id = platforms.stocklocation_id
    LEFT JOIN   orderlines      ON orderlines.order_id = orders.id
    LEFT JOIN   shipments       ON shipments.order_id = orders.id
    LEFT JOIN   shipment_lines  ON shipment_lines.shipment_id = shipments.id

    # This JOIN, together with shipment_lines, makes the query suddenly very slow (probably because of all the SUM()'s)
    LEFT JOIN   productmodelvariants_stocklocations pmv_sl ON
        pmv_sl.productmodelvariant_id = orderlines.productmodelvariant_id
        AND pmv_sl.stocklocation_id = stocklocations.id
WHERE
    orders.orderstatus_id = 2
    AND orders.order_all_to_shipment = 0
GROUP BY
    orders.id

问题

所以我计算了这个查询的4个速度(450个结果在所有情况下);

  1. 没有LEFT JOIN shipment_lines且没有LEFT JOIN productmodelvariants_stocklocations
  2. 仅限LEFT JOIN shipment_lines
  3. 仅限LEFT JOIN productmodelvariants_stocklocations
  4. 同时使用2.3.
  5. 以下是结果速度;

    1. 0.146秒
    2. 1.975秒
    3. 0.234秒
    4. 4.619秒
    5. 表格中的行

      • orderlines中的行:24528
      • shipment_lines中的行:6345
      • productmodelvariants_stocklocations中的行:1819

      结论

      正如您所看到的那样2.3.4.)都参加了比赛; SQL开始破坏汗水。

      我想知道是否有比我更多(我的)SQL知识的人知道一种改变查询上下文的方法来提升它。

      我还注意到,在执行4.并引用COALESCE(SUM()时,我很容易获得0.81.0秒。

      更新

      EXPLAIN EXTENDED

      EXPLAIN EXTENDED

2 个答案:

答案 0 :(得分:2)

您正在创建交叉联接,因为未能在shipment.status

上指定join子句

尝试重新组织您的查询:

SELECT A.*, 
    orders_id,
    customers.lastname,
    customers.priority,
#    shipments.status,
    pmv_sl.productmodelvariant_id,
    pmv_sl.nr AS pmv_nr,
    orderlines_nr_count,
    shipment_lines_nr_count
FROM (
  SELECT
      #orders.*,
      orders.id AS orders_id,
#      shipments.status,
      COALESCE(SUM(orderlines.nr), 0) AS orderlines_nr_count,
      COALESCE(SUM(shipment_lines.nr), 0) AS shipment_lines_nr_count
  FROM orders
      LEFT JOIN   orderlines      ON orderlines.order_id = orders.id
      LEFT JOIN   shipments       ON shipments.order_id = orders.id
      LEFT JOIN   shipment_lines  ON shipment_lines.shipment_id = shipments.id

  WHERE orders.orderstatus_id = 2
   AND orders.order_all_to_shipment = 0
  GROUP BY 
      orders.id,
      orderlines.productmodelvariant_id,
      stocklocations.id
) orders
    INNER JOIN  customers       ON customers.id = orders.customer_id
    INNER JOIN  platforms       ON platforms.id = orders.platform_id
    INNER JOIN  stocklocations  ON stocklocations.id = platforms.stocklocation_id
    LEFT JOIN   productmodelvariants_stocklocations pmv_sl ON
      pmv_sl.productmodelvariant_id = orderlines.productmodelvariant_id
      AND pmv_sl.stocklocation_id = stocklocations.id
GROUP BY
    orders.id

然后找出装运状态的位置。

答案 1 :(得分:1)

您的查询是针对任何给定订单在订单和货件之间进行笛卡尔联接。更好的方法是在进行连接之前将所有内容汇总到order_id级别:

SELECT
    #orders.*,
    orders.id,
    customers.lastname,
    customers.priority,
    shipments.status,
    pmv_sl.productmodelvariant_id,
    pmv_sl.nr AS pmv_nr,
    COALESCE(ol.orderlines_nr_count, 0) AS orderlines_nr_count,
    COALESCE(sl.shipment_lines_nr_count, 0) AS shipment_lines_nr_count
FROM orders
    INNER JOIN  customers       ON customers.id = orders.customer_id
    INNER JOIN  platforms       ON platforms.id = orders.platform_id
    INNER JOIN  stocklocations  ON stocklocations.id = platforms.stocklocation_id
    LEFT JOIN  
    (select order_id, SUM(orderlines.nr) as orderline_nr_count
     from orderlines
     group by order_id
    ) ol ON ol.order_id = orders.id
    LEFT JOIN   shipments       ON shipments.order_id = orders.id
    LEFT JOIN
    (select order_id, SUM(shipment_lines.nr) shipment_lines_nr_count
     from shipment_lines 
     group by order_id
    ) sl ON sl.shipment_id = shipments.id

    # This JOIN, together with shipment_lines, makes the query suddenly very slow (probably because of all the SUM()'s)
    LEFT JOIN   productmodelvariants_stocklocations pmv_sl ON
        pmv_sl.productmodelvariant_id = orderlines.productmodelvariant_id
        AND pmv_sl.stocklocation_id = stocklocations.id
WHERE
    orders.orderstatus_id = 2
    AND orders.order_all_to_shipment = 0
GROUP BY
    orders.id

这是一个近似值,因为我看到的唯一聚合函数是订单行和装运行。例如,如果每个订单有多个货件,您必须弄清楚如何将其压缩为一个状态(您的原始查询会随意选择一个,此查询也是如此)。

如果您只将group by级别的表/子查询连接在一起,则不需要最后的order_id