极慢的SQL选择查询

时间:2012-01-18 15:03:13

标签: mysql profiling

以下查询:

SELECT 
  `so`.*,
  IF(
    ISNULL(`ips`.`border`),
    `io`.`cdborder`,
    `ips`.`border`
  ) AS order_status,
  IF(
    ISNULL(`ips`.`status`),
    `io`.`cdstatus`,
    `ips`.`status`
  ) AS order_state,
  `io`.*,
  IF(
    ISNULL(`ips`.`sale`),
    `iol`.`regelstatus`,
    `ips`.`sale`
  ) AS order_line_status 
FROM
  `sales_order` AS `so` 
  INNER JOIN `sales_flat_order_item` AS `soi` 
    ON soi.order_id = so.entity_id 
  LEFT JOIN `import`.`import_orders` AS `io` 
    ON so.atorder_id = io.cdorder 
    AND so.cdadmin = io.cdadmin 
    AND (error_msg IS NULL 
      OR error_msg = "") 
  LEFT JOIN `import`.`import_orderlines` AS `iol` 
    ON iol.cdorder = so.atorder_id 
    AND iol.cdadmin = so.cdadmin 
  LEFT JOIN `import`.`import_purchase_sales` AS `ips` 
    ON so.atorder_id = ips.order 
WHERE (soi.sku IS NULL) 
  OR (
    soi.sku = iol.cdproduct 
    AND (
      soi.atorder_line = iol.nrordrgl
    ) 
    AND (
      iol.atg != soi.qty_shipped 
      OR iol.at != soi.qty_invoiced 
      OR iol.atb != soi.qty_ordered
    )
  ) 
GROUP BY `so`.`atorder_id`,
  `so`.`cdadmin` 
ORDER BY `io`.`modification_date_order` ASC 
LIMIT 200 

需要4分钟才能执行!怎么会这样?说明如下:

id     select_type     table     type         possible_keys         key         key_len     ref                                         rows     Extra
1      SIMPLE          so        index        PRIMARY               order_id    32          NULL                                        127828   Using temporary; Using filesort
1      SIMPLE          io        eq_ref       PRIMARY,error_msg     PRIMARY     261         livetest3.so.order_id,livetest3.so.cdadmin  1     
1      SIMPLE          soi       ref          IDX_ORDER             IDX_ORDER   4           livetest3.so.entity_id                      2             
1      SIMPLE          iol       ref          cdorder               cdorder     258         livetest3.so.order_id                       6        Using where
1      SIMPLE          ips       ref          sale_order            sale_order  32          livetest3.so.order_id                       3

我尝试了多个查询分析器工具,但没有向我显示有关查询哪个部分太慢的详细信息......

'so'表只包含130k行......即使有一堆左连接也不应该这么慢......有什么想法吗?

3 个答案:

答案 0 :(得分:1)

EXPLAIN为您提供了所有必需的信息。 Using temporary; Using filesort部分是缓慢的部分。

答案 1 :(得分:1)

主键似乎是order_id,但您的查询根本无法使用它。如果您在sku上创建索引,则查询应该运行得更快。

请注意,还有进一步改进的余地,但我首先要在sku上创建一个索引,然后重新运行查询以查看它现在的执行情况。

答案 2 :(得分:1)

如果不确切知道您想要从数据中得到什么,您的查询就会有一个“soi.sku IS NULL”的实例,这意味着对该别名的LEFT JOIN。你有一个正常的连接表明你总是想要一个记录匹配“soi”你的意思是把它带到LEFT JOIN吗?如果你总是想要“soi”,那么我会删除查询中“soi.sku IS NULL OR”的部分。

除此之外,查询本身看起来还不错,但是,我会确保你明确地拥有以下索引。

Table                         Index
Sales_Order                   (atorder_id, ccadmin)
import.import_orderlines      (cdorder, cdadmin)
import.import_orders          (cdorder, cdadmin)
import.import_purchase_sales  (order)

然后,改变

SELECT ... 

SELECT STRAIGHT_JOIN ...