加快慢速3表MYSQL查询

时间:2015-09-15 19:57:13

标签: php mysql database

我在电子商务网站查询3个表格。

订单表:

id
order_number
name
etc...

order_lines表:

id
order_number
sku
quantity
etc.

产品表

id
sku
title
ship_by (INT)
etc.

order_number 订单表链接到 order_lines 表。 SKU order_lines 表链接到产品表。

请注意产品表中的 ship_by 列,这表示将向哪个供应商发货。查询需要为特定供应商提取订单。订单可能包含不同供应商销售的商品。

这是我设法凑齐的查询:

SELECT 
    orders.`order_number`               as `orderId`,
    orders.`shipping`                   as `fPostageCost`,
     FROM_UNIXTIME(orders.`time`)       as `dReceievedDate`,
    (
    CASE orders.`dob`
    WHEN 'COURIER 3 DAY' THEN 'UK_SellersStandardRate'
    WHEN 'COURIER 24 HOUR' THEN 'UK_OtherCourier24'
    ELSE orders.`dob`
    END
    )                       
    ...(plus a number more)

 FROM orders
 INNER JOIN order_lines
 ON   orders.order_number = order_lines.order_number
 WHERE 
       ( 
         (SELECT COUNT(order_lines.sku) 
          FROM order_lines, products 
          WHERE order_lines.sku = products.sku 
          AND products.ship_by = 1 
          AND order_lines.order_number = orders.order_number) > 0 
       )
       AND ( orders.`printed` = 'N' OR orders.`printed` IS NULL )
       AND orders.status = 'Awaiting Despatch'
       AND ( orders.payment_status = 'Success' OR orders.payment_status = 'Paypal Paid' OR orders.payment_status = 'Manual Payment' )
  GROUP BY orders.`order_number`
  ORDER BY orders.order_number ASC

执行查询大约需要7秒钟。

如果我删除了行' AND order_lines.order_number = orders.order_number'从第二个SELECT查询开始,它几乎立即执行,但如果没有这一行,它就不会像我需要的那样工作。

除了添加' ship_by'列到order_lines表(由于我不得不改变很多php代码,我不愿意这样做),有没有办法修改这个查询以加快它的速度?

查询是从PHP外部运行的,所以它必须是一个纯粹的mysql查询。

以下是查询的EXPLAIN:

id  select_type         table        type     possible_keys     key         key_len     ref                                     rows    Extra
1   PRIMARY             order_lines  ALL      NULL              NULL        NULL        NULL                                    9627    Using temporary; Using filesort
1   PRIMARY             orders       eq_ref   order_idx         order_idx   17          .order_lines.order_number   1       Using where
2   DEPENDENT SUBQUERY  order_lines  ALL      NULL              NULL        NULL        NULL                                    9627    Using where
2   DEPENDENT SUBQUERY  products     ref      sku_2,sku,sku_3   sku_2       63          order_lines.prod_code   11      Using where

由于

3 个答案:

答案 0 :(得分:1)

您的order_lines表至少需要order_number上的索引。我们需要查看架构以便最好地选择一个架构。也许复合指数会在其他领域加快速度。

但是在选择索引更改时,必须仔细权衡系统中的其他查询,以及对插入和更新速度的影响。

目标不应该是以90%为代价快速制作10%的应用程序。

要显示非常有用的信息,请发布show create table tableName相关的表名。 (而不是自由地描述它,就像我的桌子有这个和那个)。我们需要查看订单,订单行,产品的架构。

Create Index

上的手册页

答案 1 :(得分:1)

Idk表格在您的内联视图中有多大,但如果它很大则表示 它可能有助于使用联合而不必查询每个记录的视图。

类似的东西。

    SELECT L1*
FROM 
(SELECT 
    orders.`order_number`               as `orderId`,
    0                                   AS  SKU_CNT,
    orders.`shipping`                   as `fPostageCost`,
     FROM_UNIXTIME(orders.`time`)       as `dReceievedDate`,
    (
    CASE orders.`dob`
    WHEN 'COURIER 3 DAY' THEN 'UK_SellersStandardRate'
    WHEN 'COURIER 24 HOUR' THEN 'UK_OtherCourier24'
    ELSE orders.`dob`
    END
    )                       
    ...(plus a number more)

 FROM orders
 INNER JOIN order_lines
 ON   orders.order_number = order_lines.order_number
 WHERE  ( orders.`printed` = 'N' OR orders.`printed` IS NULL )
       AND orders.status = 'Awaiting Despatch'
       AND ( orders.payment_status = 'Success' OR orders.payment_status = 'Paypal Paid' OR orders.payment_status = 'Manual Payment' )


 UNION ALL
    Select
    0                       AS  ORDERID,
    COUNT(OL.SKU)           AS  SKU_CNT,
    0                       as `fPostageCost`,
    NULL                    as `dReceievedDate`,
    ...
    FROM ORDER_LINES OL,
         PRODUCTS PR
    WHERE order_lines.sku = products.sku 
          AND products.ship_by = 1 
          AND order_lines.order_number = orders.order_number     
    GROUP BY ORDERID, ORDER_LINES_CNT, fPostageCost`, dReceievedDate`,
)L1
WHERE L1.SKU_CNT > 0
GROUP BY L1.`order_number`
ORDER BY L1.order_number ASC

答案 2 :(得分:0)

您可以将子查询替换为exists

WHERE EXISTS (SELECT 1
              FROM order_lines ol2 JOIN
                   products p2
                   ON ol2.sku = p.sku AND
                      p2.ship_by = 1 
                      ol.order_number = o.order_number
             ) AND
        . . .

但是,您的查询片段未在外部查询中使用order_lines。我怀疑你可以通过聚合摆脱它:

FROM orders o
WHERE EXISTS (SELECT 1
              FROM order_lines ol2 JOIN
                   products p2
                   ON ol2.sku = p2.sku AND
                      p2.ship_by = 1 
                      ol.order_number = o.order_number
             ) AND
        . . .

这将至少返回所有订单信息 - 并且缺少聚合可能会简化查询的其他部分。如果某些版本的查询运行得很快,那么索引可能设置得合理。