【问题标题】:Troubleshooting Wordpress/Woocommerce custom SQL query for reporting用于报告的 Wordpress/Woocommerce 自定义 SQL 查询疑难解答
【发布时间】:2015-07-27 06:14:18
【问题描述】:

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

我的 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 列表,如下所示:

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

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

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

更新/跟进:

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

【问题讨论】:

  • IN ( SELECT ... ) 结构在 5.6 之前优化得非常差。你用的是那个版本吗?
  • 如果 woocommerce 正在生成该代码,请向他们投诉。同时,我会将其归结为第 3 方软件存在问题的另一个案例。
  • 5.7 具有“查询重写”功能,可让您即时重写此类查询。解决第 3 方的缺陷是一个难题。
  • 这些都不是由 WordPress 或 WooCommerce 生成的,我只需要一份带有自定义元数据的订单报告。我不确定我使用的版本需要检查,主机上可能会有所不同。目前我直接在phpmyadmin中写这个

标签: mysql sql wordpress woocommerce query-optimization


【解决方案1】:
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 ... ) 无法优化。
  • 通过在“表”列表中加入 一个 子查询,优化器将(几乎可以肯定)从子查询开始,并对其他表执行“嵌套循环连接”。 NLJ 是执行查询的常用方法。
  • 这样的子选择没有索引,所以它需要在顺序中排在第一位,否则效率会很低。
  • 如果没有子查询,优化器通常喜欢从 WHERE 子句中包含内容的任何表开始。
  • 从子查询“表”开始的要求强于根据WHERE pm.meta_key = '_order_total' 选择表的愿望。
  • 在子查询中,唯一的“=”测试 (WHERE im.meta_value = '23563) 为该组 JOIN 提供了可能的起点。这进一步增强了它不是LEFT JOIN 的“正确”。因此,我建议使用该索引。

【讨论】:

  • 我不明白它在 FROM 中是如何工作的,但它似乎工作正常。现在尝试使用更复杂的查询来执行此操作但失败了,因为我认为我不了解这里发生的事情。
  • 即使这个查询也比典型的更复杂。我编辑了我的答案,以包括我应用到那里的一些逻辑。 My blog on building indexes 与此处部分相关。
  • 我也同意索引 meta_value 的想法,因为它在我所有不同的报告之间使用了很多,但不知道如何做到这一点。我在 phpmyadmin 中尝试了 index 链接,但出现错误:`#1170 - BLOB/TEXT 列 'meta_value' 在没有密钥长度的密钥规范中使用`,我相信这意味着我无法索引它,因为它是“ longtext" 类型 (utf8mb4_unicode_ci)
  • 哦。键值模式。慰问。
猜你喜欢
  • 1970-01-01
  • 2013-10-22
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-15
  • 1970-01-01
相关资源
最近更新 更多