我需要一些帮助来优化这个WordPress/WooCommerce查询:

SELECT
    p.ID AS order_id
    ,DATE(p.post_date) AS order_date
    ,SUBSTR(comment_content,17) AS csr
    ,SUBSTR(p.post_status,4) AS order_status
    ,UCASE(CONCAT((SELECT wp_postmeta.meta_value FROM wp_postmeta WHERE meta_key = '_billing_first_name' and wp_postmeta.post_id = p.ID),' ',(SELECT wp_postmeta.meta_value FROM wp_postmeta WHERE meta_key = '_billing_last_name' and wp_postmeta.post_id = p.ID))) AS customer
    ,(SELECT GROUP_CONCAT(DISTINCT order_item_name ORDER BY order_item_name ASC SEPARATOR ', ') FROM wp_woocommerce_order_items WHERE order_id = p.ID AND order_item_type = 'line_item' GROUP BY order_id) AS products
    ,(SELECT GROUP_CONCAT(CONCAT(serial_number,'',serial_feature_code)) FROM wp_custom_serial WHERE wp_custom_serial.order_id = p.ID GROUP BY wp_custom_serial.order_id) AS serials 
FROM
    wp_posts AS p
    INNER JOIN wp_comments AS c ON p.ID = c.comment_post_ID
    INNER JOIN wp_postmeta AS pm ON p.ID = pm.post_id
    
WHERE
    p.post_type = 'shop_order'
    AND comment_content LIKE 'Order placed by%'
GROUP BY p.ID
ORDER BY SUBSTR(comment_content,17) ASC, p.post_date DESC;

我不明白EXPLAIN告诉我的是什么,我需要一些关于如何加快它的指导.谁能描述一下,在EXPLAIN的回复中,什么表明了我的问题所在,以及在哪里可以找到答案?

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY c NULL ALL comment_post_ID NULL NULL NULL 20452 11.11 Using where; Using temporary; Using filesort
1 PRIMARY p NULL eq_ref PRIMARY,post_name,type_status_date,post_parent,post_author PRIMARY 8 db.c.comment_post_ID 1 50.00 Using where
1 PRIMARY pm NULL ref post_id post_id 8 db.c.comment_post_ID 33 100.00 Using index
2 DEPENDENT SUBQUERY wp_postmeta NULL ref post_id,meta_key post_id 8 func 33 2.26 Using where
3 DEPENDENT SUBQUERY wp_postmeta NULL ref post_id,meta_key post_id 8 func 33 2.30 Using where
4 DEPENDENT SUBQUERY wp_woocommerce_order_items NULL ref order_id order_id 8 func 2 10.00 Using where
5 DEPENDENT SUBQUERY wp_custom_serial NULL ALL NULL NULL NULL NULL 5160 10.00 Using where; Using filesort

推荐答案

查询在不同的阶段进行处理.首先处理的子句是FROM子句,然后是WHERE子句,然后是SELECT子句.那些相依子查询意味着,在处理FROM和WHERE子句之后,您将为其中each row个结果运行单独的新子查询.在你的情况下,你做的是那个的四倍.

您通常可以对此进行修改,以将这些查询从SELECT子句移到FROM子句中.

以您已有的一列,即serials列为例,我认为您可能希望将其移到FROM子句中,如下所示

SELECT p.ID                                                                                  AS order_id
     , DATE(p.post_date)                                                                     AS order_date
     , SUBSTR(comment_content, 17)                                                           AS csr
     , SUBSTR(p.post_status, 4)                                                              AS order_status
     , UCASE(CONCAT((SELECT wp_postmeta.meta_value
                     FROM wp_postmeta
                     WHERE meta_key = '_billing_first_name' and wp_postmeta.post_id = p.ID), ' ',
                    (SELECT wp_postmeta.meta_value
                     FROM wp_postmeta
                     WHERE meta_key = '_billing_last_name' and wp_postmeta.post_id = p.ID))) AS customer
     , (SELECT GROUP_CONCAT(DISTINCT order_item_name ORDER BY order_item_name ASC SEPARATOR ', ')
        FROM wp_woocommerce_order_items
        WHERE order_id = p.ID
          AND order_item_type = 'line_item'
        GROUP BY order_id)                                                                   AS products
     , serials_sub.serials
FROM wp_posts AS p
         INNER JOIN wp_comments AS c ON p.ID = c.comment_post_ID
         INNER JOIN wp_postmeta AS pm ON p.ID = pm.post_id
         LEFT JOIN (
            SELECT p.ID as post_id, GROUP_CONCAT(CONCAT(cs.serial_number, '', cs.serial_feature_code)) AS serials
            FROM wp_custom_serial cs
            JOIN wp_posts AS p ON cs.order_id = p.ID
            WHERE p.post_type = 'shop_order'
             AND comment_content LIKE 'Order placed by%'
            GROUP BY cs.order_id
         ) as serials_sub ON serials_sub.post_id = p.ID
WHERE p.post_type = 'shop_order'
  AND comment_content LIKE 'Order placed by%'
GROUP BY p.ID
ORDER BY SUBSTR(comment_content, 17) ASC, p.post_date DESC;

这里的不同之处在于,不是对每一行执行单独的查询,而是在初始的FROM子句中使用单个子查询.因此,虽然看起来可能更笨拙,但实际上这会给您带来更好的性能.

对其他子查询遵循此模式,我认为将解决您的问题.

如果感兴趣,这里有关于解释的文档.

https://dev.mysql.com/doc/refman/8.0/en/execution-plan-information.html

我推荐这本书High Performance MySQL.

Mysql相关问答推荐

嵌套MySQL语句问题

为什么我安装MySQL时不能使用3306端口?

根据当前表列的值,从SQL中的另一个表中获取数据

我可以指示MariaDB-Install-db和MariaDB忽略配置中的用户设置吗?

使用触发器markdown 10%

外部磁盘上的MySQL表空间和数据文件

如果存在N个特殊行,如何 Select 它们,其余的必须填充常规行,总行数不能超过MySQL中的X行?

Group By 查询运行速度太慢而无法正常运行

如何在 MySQL Workbench 中设置 DateTime 列的默认值?

MySql SELECT 查找包含数字的区间的时间复杂度是多少?

SQL: Select TEXT 字段的子字符串比整个值快

如何优化使用多个 LEFT JOIN 和 GROUP BY 子句的慢速 MySQL 查询?

Mysql 中相同列的相关 2 查询

为什么这个查询需要超过 5 秒才能运行?

MySQL如何在小时和分钟之间 Select 时间

MYSQL除以零警告,奇怪的行为

MYSQL REGEXP_REPLACE 在数字之后

了解 SQL 中的元组语法

MySQL Group By 和 Sum 其他列的总值

phpmyadmin没有收到要导入的数据错误,如何解决?