【问题标题】:WooCommerce Product MySQL query is taking too long with ORDER BYWooCommerce 产品 MySQL 查询使用 ORDER BY 花费的时间太长
【发布时间】:2021-01-07 05:22:15
【问题描述】:

我在 WooCommerce 中有 25000 多种产品。

我正在使用 CUSTOM MYSQL 查询来查询我的产品,因为我希望获取最少的数据,而不是在一个对象中获取整个产品。

查询工作正常,如下所示:

SELECT 
        p.ID, 
        m1.meta_value as 'cut', 
        m2.meta_value as 'polish', 
        m3.meta_value as 'symmetry', 
        m4.meta_value as 'fluor_intensity', 
        m5.meta_value as 'short_name', 
        m6.meta_value as 'total_sales_price',
        m7.meta_value as 'available',
        m8.meta_value as 'lab',
        m9.meta_value as 'shape', 
        m10.meta_value as 'size', 
        m11.meta_value as 'color', 
        m12.meta_value as 'clarity', 
        m13.meta_value as 'depth_percent', 
        m14.meta_value as 'table_percent',
        m15.meta_value as 'meas_length',
        m16.meta_value as 'meas_width',
        m17.meta_value as 'meas_depth',
        m18.meta_value as 'price_per_caret',
        m19.meta_value as 'fancy_color',
        m20.meta_value as 'fancy_intensity',
        m21.meta_value as 'image',
        m22.meta_value as 'meas_ratio',
        m23.meta_value as 'treatment',
        m24.meta_value as 'culet_size'
        FROM
         wp_u8gwgg_posts p 
            LEFT JOIN wp_u8gwgg_postmeta m1 ON p.id = m1.post_id AND m1.meta_key = '_diamond_cut' 
            LEFT JOIN wp_u8gwgg_postmeta m2 ON p.id = m2.post_id AND m2.meta_key = '_diamond_polish' 
            LEFT JOIN wp_u8gwgg_postmeta m3 ON p.id = m3.post_id AND m3.meta_key = '_diamond_symmetry' 
            LEFT JOIN wp_u8gwgg_postmeta m4 ON p.id = m4.post_id AND m4.meta_key = '_diamond_fluor_intensity' 
            LEFT JOIN wp_u8gwgg_postmeta m5 ON p.id = m5.post_id AND m5.meta_key = '_diamond_shortname' 
            LEFT JOIN wp_u8gwgg_postmeta m6 ON p.id = m6.post_id AND m6.meta_key = '_price' 
            LEFT JOIN wp_u8gwgg_postmeta m7 ON p.id = m7.post_id AND m7.meta_key = '_diamond_available' 
            LEFT JOIN wp_u8gwgg_postmeta m8 ON p.id = m8.post_id AND m8.meta_key = '_diamond_lab' 
            LEFT JOIN wp_u8gwgg_postmeta m9 ON p.id = m9.post_id AND m9.meta_key = '_diamond_shape' 
            LEFT JOIN wp_u8gwgg_postmeta m10 ON p.id = m10.post_id AND m10.meta_key = '_diamond_size' 
            LEFT JOIN wp_u8gwgg_postmeta m11 ON p.id = m11.post_id AND m11.meta_key = '_diamond_color' 
            LEFT JOIN wp_u8gwgg_postmeta m12 ON p.id = m12.post_id AND m12.meta_key = '_diamond_clarity' 
            LEFT JOIN wp_u8gwgg_postmeta m13 ON p.id = m13.post_id AND m13.meta_key = '_diamond_depth_percent' 
            LEFT JOIN wp_u8gwgg_postmeta m14 ON p.id = m14.post_id AND m14.meta_key = '_diamond_table_percent' 
            LEFT JOIN wp_u8gwgg_postmeta m15 ON p.id = m15.post_id AND m15.meta_key = '_diamond_meas_length' 
            LEFT JOIN wp_u8gwgg_postmeta m16 ON p.id = m16.post_id AND m16.meta_key = '_diamond_meas_width' 
            LEFT JOIN wp_u8gwgg_postmeta m17 ON p.id = m17.post_id AND m17.meta_key = '_diamond_meas_depth' 
            LEFT JOIN wp_u8gwgg_postmeta m18 ON p.id = m18.post_id AND m18.meta_key = '_diamond_price_per_carat' 
            LEFT JOIN wp_u8gwgg_postmeta m19 ON p.id = m19.post_id AND m19.meta_key = '_diamond_fancy_color'
            LEFT JOIN wp_u8gwgg_postmeta m20 ON p.id = m20.post_id AND m20.meta_key = '_diamond_fancy_intensity'
            LEFT JOIN wp_u8gwgg_postmeta m21 ON p.id = m21.post_id AND m21.meta_key = '_knawatfibu_url'
            LEFT JOIN wp_u8gwgg_postmeta m22 ON p.id = m22.post_id AND m22.meta_key = '_diamond_meas_ratio'
            LEFT JOIN wp_u8gwgg_postmeta m23 ON p.id = m23.post_id AND m23.meta_key = '_diamond_treatment'
            LEFT JOIN wp_u8gwgg_postmeta m24 ON p.id = m24.post_id AND m24.meta_key = '_diamond_culet_size'
            WHERE p.post_type = "product" 
        ORDER BY total_sales_price+0 ASC
        LIMIT 0, 12

当我在查询中添加ORDER BY total_sales_price+0 ASC 时,真正的难题发生了。

因此,当我不添加 ORDER BY 子句时,查询会在 0.02s 左右为我提供结果 与ORDER BY 相同的查询在 9.4s

左右为我提供了结果

问题:

  1. 如何使用ORDER BY 子句减少获取记录的时间?
  2. 有没有什么方法可以让这个查询对最终用户更好地执行?

提前致谢。

【问题讨论】:

  • 显示explain select rest-of-your-query的输出,有和没有顺序,以及show create table wp_u8gwgg_postsshow create table wp_u8gwgg_postmeta的输出
  • 您有没有 _price 元键值的产品吗?
  • 这里的问题是,当查询要对 25000 条记录中的数据进行排序(使用 ORDER BY 时)时,与左连接一起花费的时间太长。否则,带有 LEFT JOIN 的查询也给了我完美的时机。
  • 所有产品都有 _price 元键。没有元密钥为空的产品
  • 那么无论是两个 LEFT JOIN 还是 24 对查询性能没有影响(或只有微不足道的影响)?

标签: php mysql wordpress woocommerce


【解决方案1】:

您可以先使用子查询过滤 wp_u8gwgg_posts 和 price,然后过滤已排序的行数。然后只剩下加入其余的。这应该会限制您需要加入的行数。

select
   p.id,
   m1.meta_value as 'cut',
   m2.meta_value as 'polish',
   m3.meta_value as 'symmetry',
   m4.meta_value as 'fluor_intensity',
   m5.meta_value as 'short_name',
   p.total_sales_price,
   m7.meta_value as 'available',
   m8.meta_value as 'lab',
   m9.meta_value as 'shape',
   m10.meta_value as 'size',
   m11.meta_value as 'color',
   m12.meta_value as 'clarity',
   m13.meta_value as 'depth_percent',
   m14.meta_value as 'table_percent',
   m15.meta_value as 'meas_length',
   m16.meta_value as 'meas_width',
   m17.meta_value as 'meas_depth',
   m18.meta_value as 'price_per_caret',
   m19.meta_value as 'fancy_color',
   m20.meta_value as 'fancy_intensity',
   m21.meta_value as 'image',
   m22.meta_value as 'meas_ratio',
   m23.meta_value as 'treatment',
   m24.meta_value as 'culet_size' 
from
   (
      select
         aa.id,
         m6.meta_value as 'total_sales_price' 
      from
         wp_u8gwgg_posts aa 
         left join
            wp_u8gwgg_postmeta m6 
            ON aa.id = m6.post_id 
            and m6.meta_key = '_price' 
      where
         aa.post_type = "product" 
      order by
         m6.meta_value + 0 asc limit 0,
         12 
   )
   as p 
   left join
      wp_u8gwgg_postmeta m1 
      on p.id = m1.post_id 
      and m1.meta_key = '_diamond_cut' 
   left join
      wp_u8gwgg_postmeta m2 
      on p.id = m2.post_id 
      and m2.meta_key = '_diamond_polish' 
   left join
      wp_u8gwgg_postmeta m3 
      on p.id = m3.post_id 
      and m3.meta_key = '_diamond_symmetry' 
   left join
      wp_u8gwgg_postmeta m4 
      on p.id = m4.post_id 
      and m4.meta_key = '_diamond_fluor_intensity' 
   left join
      wp_u8gwgg_postmeta m5 
      on p.id = m5.post_id 
      and m5.meta_key = '_diamond_shortname' 
   left join
      wp_u8gwgg_postmeta m7 
      on p.id = m7.post_id 
      and m7.meta_key = '_diamond_available' 
   left join
      wp_u8gwgg_postmeta m8 
      on p.id = m8.post_id 
      and m8.meta_key = '_diamond_lab' 
   left join
      wp_u8gwgg_postmeta m9 
      on p.id = m9.post_id 
      and m9.meta_key = '_diamond_shape' 
   left join
      wp_u8gwgg_postmeta m10 
      on p.id = m10.post_id 
      and m10.meta_key = '_diamond_size' 
   left join
      wp_u8gwgg_postmeta m11 
      on p.id = m11.post_id 
      and m11.meta_key = '_diamond_color' 
   left join
      wp_u8gwgg_postmeta m12 
      on p.id = m12.post_id 
      and m12.meta_key = '_diamond_clarity' 
   left join
      wp_u8gwgg_postmeta m13 
      on p.id = m13.post_id 
      and m13.meta_key = '_diamond_depth_percent' 
   left join
      wp_u8gwgg_postmeta m14 
      on p.id = m14.post_id 
      and m14.meta_key = '_diamond_table_percent' 
   left join
      wp_u8gwgg_postmeta m15 
      on p.id = m15.post_id 
      and m15.meta_key = '_diamond_meas_length' 
   left join
      wp_u8gwgg_postmeta m16 
      on p.id = m16.post_id 
      and m16.meta_key = '_diamond_meas_width' 
   left join
      wp_u8gwgg_postmeta m17 
      on p.id = m17.post_id 
      and m17.meta_key = '_diamond_meas_depth' 
   left join
      wp_u8gwgg_postmeta m18 
      on p.id = m18.post_id 
      and m18.meta_key = '_diamond_price_per_carat' 
   left join
      wp_u8gwgg_postmeta m19 
      on p.id = m19.post_id 
      and m19.meta_key = '_diamond_fancy_color' 
   left join
      wp_u8gwgg_postmeta m20 
      on p.id = m20.post_id 
      and m20.meta_key = '_diamond_fancy_intensity' 
   left join
      wp_u8gwgg_postmeta m21 
      on p.id = m21.post_id 
      and m21.meta_key = '_knawatfibu_url' 
   left join
      wp_u8gwgg_postmeta m22 
      on p.id = m22.post_id 
      and m22.meta_key = '_diamond_meas_ratio' 
   left join
      wp_u8gwgg_postmeta m23 
      on p.id = m23.post_id 
      and m23.meta_key = '_diamond_treatment' 
   left join
      wp_u8gwgg_postmeta m24 
      on p.id = m24.post_id 
      and m24.meta_key = '_diamond_culet_size' 
order by
   p.total_sales_price + 0 asc

【讨论】:

  • 嘿@Vlam,谢谢你的回答。就我而言,它确实表现得很好。我只是对此表示怀疑。这只是ORDERtotal_sales_price 的一列的情况。如果我必须添加多个ORDER BY 子句,例如shapesizecolor,该怎么办?如何在子查询中实现它?
  • 编辑:为了澄清上面的评论,我知道如何在子查询中实现这些东西,但是添加多个 ORDER BY 意味着我们必须添加多个左连接。也是。但是情况会和现在一样。所以我想问一下我们可以在那里进行任何改进吗?
  • 如果你继续在子查询中添加order by,那么它将再次陷入困境。我没有看到任何优化它的方法。
【解决方案2】:

最后,我实现了 WooCommerce 的 查找表 概念。

您可以在此处查看文档:https://developer.woocommerce.com/2019/04/01/performance-improvements-in-3-6/

在应用查找表之前,我的搜索时间是15-20 seconds。 现在它下降到1.5-3 seconds

我只需要将查询更改为:

SELECT 
    p.ID, 
    p.cut as 'cut', 
    p.polish as 'polish', 
    p.symmetry as 'symmetry', 
    p.fluor_intensity as 'fluor_intensity', 
    p.short_name as 'short_name', 
    p.total_sales_price as 'total_sales_price',
    p.available as 'available',
    p.labshape as 'labshape',
FROM
    wp_u8gwgg_app_data p
ORDER BY total_sales_price+0 ASC
LIMIT 0, 12

Left Joins 现在是GONE,我可以在 1 个表下查看所有数据。

如果有人正在寻找相同的,可以实现查找表以优化速度。

【讨论】:

  • total_sales_price 设为数字列; +0 正在损害性能。然后添加INDEX(total_sales_price)(我想你正在找出为什么 WP 的架构设计有问题。)
【解决方案3】:

两个加速:

这就是我所说的第一个建议的意思:

首先,让我们找到你想要的 12 件物品:

SELECT  p2.ID, 
        m6.meta_value
    FROM wp_u8gwgg_posts p2 
    JOIN wp_u8gwgg_postmeta m6 ON p2.id = m6.post_id
                              AND m6.meta_key = '_price' 
    ORDER BY total_sales_price+0 ASC
    LIMIT 0, 12

请注意,我使用的是JOIN,而不是LEFT JOIN。不要使用LEFT,除非“正确”表确实是可选的。拥有上面链接中提到的改进的索引将有助于这个查询。

接下来,将其用作子查询来完成其余工作:

SELECT  x.ID, 
        m1.meta_value as 'cut', 
        m2.meta_value as 'polish', 
        m3.meta_value as 'symmetry', 
        m4.meta_value as 'fluor_intensity', 
        x.meta_value as 'short_name',          -- note
        m6.meta_value as 'total_sales_price',
        m7.meta_value as 'available',
        ...
    FROM ( ... the query above ...)
    JOIN wp_u8gwgg_posts p2 USING(ID)    -- again (to get other columns)
    LEFT JOIN ...
    LEFT JOIN ...   -- the rest of the JOINs  (skip m6)
    ORDER BY total_sales_price+0 ASC   -- yes, repeated
    -- no need for LIMIT, unless the JOINs lead to dups

如果priceposts 表中的numeric 列会更好,但这违反了 WP 和 Woo 的一般性,其中值(s) 您想要筛选或排序的依据不容易访问。

【讨论】:

  • 我认为你是对的,total_sales_price 应该是数字。这种改变是被接受的。但是我现在需要的查找表查询运行良好。它在 0.0015 秒内给了我结果。形成数据并将其显示到前端,大约需要 1.5-2 秒。
  • 0.0015 seconds 闻起来像查询缓存结果。使用SELECT SQL_NO_CACHE ... 计时
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 2019-12-28
  • 2018-01-08
  • 2012-09-03
  • 1970-01-01
相关资源
最近更新 更多