SQL 选择查询速度极慢

发布于 12-28 04:21 字数 2277 浏览 2 评论 0原文

以下查询:

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 行...即使有一堆左连接,它也应该不要这么慢...有什么想法吗?

The following query:

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 

Is taking 4 minutes to execute! How can this be? Explain shows the following:

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

I tried multiple query profiler tools but none show me detailed information about which part of the query is so slow...

The 'so' table only contains 130k rows... Even with a bunch of left joins it should not be this slow... Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

无敌元气妹2025-01-04 04:21:06

解释为您提供了所有必需的信息。 使用临时;使用 filesort 部分是缓慢的部分。

The EXPLAIN gave you all the required information. The Using temporary; Using filesort part is the slow part.

旧人哭2025-01-04 04:21:06

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

请注意,还有更多改进的空间,但我首先在 sku 上创建索引,然后再次重新运行查询以查看它现在的执行情况。

It seems that the primary key is order_id but your query can't use it at all. If you create an index on sku your query should run faster.

Note that there's room for more improvement but I'd start by creating an index on sku and re-run the query again to see how it performs now.

泪眸﹌2025-01-04 04:21:06

该查询必须从“so”表中检索所有 127828 条记录,将它们放入临时表中,然后对每条记录执行所有 IF,然后按照分组依据的字段进行排序。根据机器的速度、负载,尤其是可用内存量,这个执行时间并非不现实。

The query has to retrieve all 127828 records from the "so" table, put them into a temporary table, then execute all the IFs for each record, then sort after the fields you grouped by. Depending on the speed of the machine, it's load and especially the amount of available memory this execution time is not unrealistic.

2025-01-04 04:21:06

在不确切知道您想要从数据中得到什么的情况下,您的查询有一个“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 ...

Without knowing exactly what you WANT out of the data, your query has an instance of "soi.sku IS NULL" which would imply a LEFT JOIN to that alias. You had a normal join indicating you ALWAYS wanted a record match to "soi" Did you mean to take that to a LEFT JOIN instead? If you ALWAYS want the "soi", then I would remove the where "soi.sku IS NULL OR" portion of the query.

Other than that, the query itself looks ok, however, I would ensure you explicitly have the following indexes.

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

Then, change

SELECT ... 

to

SELECT STRAIGHT_JOIN ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文