故障排除 Wordpress/Woocommerce 自定义 SQL 报告查询

Troubleshooting Wordpress/Woocommerce custom SQL query for reporting

希望这是一个正确的论坛,我的问题似乎与堆栈交换社区重叠,所以这似乎是最好的。

我的 wordpress 网站上有一些关于我的 WooCommerce 订单的自定义报告。我有一个查询只是在本地冻结,这意味着在我的本地主机中,我的 CPU 达到 100%,而且它永远不会完成,我不明白为什么。到此为止,查询是:

SELECT SUM(postmeta.meta_value)
FROM pca_postmeta AS postmeta
LEFT JOIN pca_woocommerce_order_items AS orders ON orders.order_id = postmeta.post_id
WHERE postmeta.meta_key = '_order_total'
AND orders.order_item_id IN (
    SELECT item_meta.order_item_id 
    FROM pca_woocommerce_order_itemmeta AS item_meta 
    LEFT JOIN pca_woocommerce_order_items AS orders ON item_meta.order_item_id = orders.order_item_id 
    LEFT JOIN pca_posts AS posts ON posts.ID = orders.order_id 
    WHERE item_meta.meta_value = '23563' 
    AND posts.post_status IN ('wc-processing','wc-completed') 
    GROUP BY orders.order_id
)

如您所见,此处的目标是获取此特定活动 (23563) 中所有订单的总和。嵌套查询本身完全按照预期工作,仅返回一个 ID 列表,如下所示:

注意: 有点好奇如果 2.6289 秒很长,它只返回 65 秒,尽管总共有 148220 秒

问题是这个查询似乎不喜欢嵌套部分。有什么建议么?完全不同的方法?

P.S。我在其他时候也使用该嵌套查询,在我的 php 报告 class 中按活动 ID 表示所有订单。但是对于我的问题PHP与它无关。

UPDATE/FOLLOW UP:

是否可以按照此处所述将其转换为联接:Using a SELECT statement within a WHERE clause?我对我的 SQL 有点了解,所以不确定我该怎么做,但看起来很有希望

GROUP BY  orders.order_id

没有意义,因为您只选择了 order_item_id

pca_woocommerce_order_itemmeta 会受益于

INDEX(meta_value, order_item_id)

这个 可能 是一个等效的查询,但避免了 IN(SELECT...):

SELECT  SUM(pm.meta_value)
    FROM  
      ( SELECT  im.order_item_id
            FROM  pca_woocommerce_order_itemmeta AS im
            LEFT JOIN  pca_woocommerce_order_items AS o
                             ON im.order_item_id = o.order_item_id
            LEFT JOIN  pca_posts AS posts ON posts.ID = o.order_id
            WHERE  im.meta_value = '23563'
              AND  posts.post_status IN ('wc-processing','wc-completed')
            GROUP BY  o.order_id 
      ) AS w
    JOIN  pca_woocommerce_order_items AS o ON w.order_item_id = o.order_item_id
    JOIN  pca_postmeta AS pm ON o.order_id = pm.post_id
    WHERE  pm.meta_key = '_order_total'

编辑

我所做的一些原则。在这里,我猜测优化器将如何处理各种可能的查询公式。

  • 我去掉了 LEFT -- 这 可能 改变了输出。但是我需要避免无法优化的 LEFT JOIN ( SELECT ... )
  • 通过在 "tables" 的列表中加入 一个 子查询,优化器将(几乎可以肯定)从子查询开始并执行 "Nested Loop Joins" 到其他tables。 NLJ 是执行查询的常用方法。
  • 像这样的subselect是没有索引的,所以需要排在第一位,否则效率很低
  • 在没有子查询的情况下,优化器通常喜欢从 table 在 WHERE 子句中包含的内容开始。
  • 从子查询"table"开始的要求强于基于WHERE pm.meta_key = '_order_total'选择table的愿望。
  • 在子查询中,唯一的“=”测试 (WHERE im.meta_value = '23563) 为该组 JOIN 提供了可能的起点。由于它不是 LEFT JOIN 的 'right',因此进一步增强了这一点。因此,我建议 index.