【问题标题】:Optimizing custom Wordpress SQL query for fetching usermeta data优化自定义 Wordpress SQL 查询以获取用户元数据
【发布时间】:2021-11-01 22:01:24
【问题描述】:

我有以下查询,它有效。但由于它的堆积,处理时间非常长。因此,我需要帮助以更快地获得此查询。

SQL 查询

在查询中 PRODUCT_ID 应替换为 ' ' 和 productID 编号。

SELECT
    b.order_id,
    customer_meta.meta_value AS customer_id,
    users.user_email,
    qty_table.meta_value AS qty,
    user_meta1.meta_value AS firstname,
    user_meta2.meta_value AS lastname,
    user_meta3.meta_value AS company,
    user_meta4.meta_value AS address,
    user_meta5.meta_value AS city,
    user_meta6.meta_value AS postcode,
    user_meta7.meta_value AS state,
    user_meta8.meta_value AS user_phone
FROM
    wp_woocommerce_order_itemmeta a,
    wp_woocommerce_order_items b,
    wp_postmeta customer_meta,
    wp_users users,
    wp_woocommerce_order_itemmeta qty_table,
    wp_usermeta user_meta1,
    wp_usermeta user_meta2,
    wp_usermeta user_meta3,
    wp_usermeta user_meta4,
    wp_usermeta user_meta5,
    wp_usermeta user_meta6,
    wp_usermeta user_meta7,
    wp_usermeta user_meta8
WHERE
    a.meta_key = '_product_id'
    AND a.meta_value = PRODUCT_ID
    AND a.order_item_id = b.order_item_id
    AND customer_meta.meta_key = '_customer_user'
    AND customer_meta.post_id = b.order_id
    AND user_meta1.meta_key = 'first_name'
    AND user_meta1.user_id = users.id
    AND user_meta2.meta_key = 'last_name'
    AND user_meta2.user_id = users.id
    AND user_meta3.meta_key = 'billing_company'
    AND user_meta3.user_id = users.id
    AND user_meta4.meta_key = 'billing_address_1'
    AND user_meta4.user_id = users.id
    AND user_meta5.meta_key = 'billing_city'
    AND user_meta5.user_id = users.id
    AND user_meta6.meta_key = 'billing_postcode'
    AND user_meta6.user_id = users.id
    AND user_meta7.meta_key = 'billing_state'
    AND user_meta7.user_id = users.id
    AND user_meta8.meta_key = 'billing_phone'
    AND user_meta8.user_id = users.id
    AND users.ID = customer_meta.meta_value
    AND qty_table.meta_key = '_qty'
    AND qty_table.order_item_id = b.order_item_id
ORDER BY user_meta3.meta_value ASC

我需要所有信息,因为我想列出已购买给定产品的所有用户及其名字、姓氏、公司、地址、邮政编码等。所以查询本身是有效的,但在处理时间上是一个杀手。

我可以使用 max( CASE WHEN ... ... THEN ...END ) 作为 a_name 但我只知道如果我使用左连接才能成功。

关于如何让这个查询更好地运行的任何提示?

【问题讨论】:

    标签: mysql sql wordpress optimization query-optimization


    【解决方案1】:

    WP,你在听吗? WooCommerce,你在听吗?我已经厌倦了优化您的数据库应用程序。

    首先,EAV 是一种糟糕的架构设计。但我不会为此吐槽。我将指出可能丢失或格式错误的索引:

    wp_usermeta:  PRIMARY KEY(user_id, meta_key)
    

    没有添加任何(191)

    wp_woocommerce_order_itemmeta 也是如此。

    我可能会有更多的滥用;请为正在使用的表格提供SHOW CREATE TABLE

    【讨论】:

    【解决方案2】:

    多年后,在与@RickJames 交谈后,这里是您问题的另一个答案。

    1. 您已将查询从逗号连接重构为左连接。那很好。您的逗号连接语法从结果集中省略了缺少元数据的用户。

    2. 如果您还没有这样做,请确保升级您的 MySQL 服务器,使其版本为 5.7 或更高版本。如果您使用 MariaDB,请将其升级为 10.3 或更高版本。该版本对性能很重要。

    3. 安装并使用 WordPress 插件 Index WP MySQL for Speed。里克和我把它放在一起来准确地解决你的问题。它重新索引 wp_usermeta(和其他一些 WordPress 表)以提高此类查询的效率。

    或者,如果您不想使用插件来重新索引您的表,you can do it yourself 通过 phpmyadmin 或其他一些 SQL 客户端。 (如果您停留在旧版本的 MySQL 上,这些语句将不起作用。该插件包含旧版本的 workaround,这有点太复杂,无法在 StackOverflow 答案中解释。)

    ALTER TABLE wp_usermeta ENGINE=InnoDB, ROW_FORMAT=Dynamic;
    ALTER TABLE wp_usermeta ADD UNIQUE KEY umeta_id (umeta_id);
    ALTER TABLE wp_usermeta DROP PRIMARY KEY;
    ALTER TABLE wp_usermeta ADD PRIMARY KEY (user_id, meta_key, umeta_id);
    ALTER TABLE wp_usermeta DROP KEY user_id;
    ALTER TABLE wp_usermeta DROP KEY meta_key;
    ALTER TABLE wp_usermeta ADD KEY meta_key (meta_key, user_id);
    

    这组索引允许您的查询更有效地检索那些左连接的 meta_value 属性。为什么?简而言之,该表需要在(user_id, meta_key) 上建立索引。而在 InnoDB 中,表中的数据实际上存储在主键的索引中(称为clustered index)。所以 MySQL 可以非常快速的检索到你需要的 meta_values。

    【讨论】:

    • 愚蠢的问题,但我不是那么先进:如果我想通过shop_order cpt中的电话号码查询订单,我应该在哪里添加主键?在 usermeta 中还是在 postmeta 中?其次,为什么 WP 和 WC 核心提交者没有对此做任何事情?
    • 如果不知道订单电话号码与订单(postmeta)或用户(usermeta)相关联,我无法开始回答您的第一个问题。无论如何,如果您“不那么先进”,则不应更改主键,除非您愿意丢失表。阅读此plumislandmedia.net/index-wp-mysql-for-speed/tables_and_keys。它描述了我的回答中提到的 WordPress 插件中所做的关键更改。
    • 至于核心团队为什么没有重新设计他们的索引,我不知道。我希望他们有一天会通过添加更好的索引使插件过时。他们无法在不破坏许多站点的情况下修改表定义。
    • 是的,它们与订单号相关联;我使用了这个插件,它帮助很大!
    【解决方案3】:

    添加 Rick James 描述的索引将使原始查询更快。

    但我已设法将其更改为使用 LEFT JOIN,这是迄今为止最快的,如果其他人需要它,则会在此处显示:

    SELECT
      b.order_id, 
      customer_meta.meta_value as customer_id,
      u.display_name as customer_name,
      u.user_email, 
      qty_table.meta_value as qty,
      um_last_name.meta_value as last_name,
      um_first_name.meta_value as first_name,
      um_address1.meta_value as address1,
      um_address2.meta_value as address2,
      um_address_city.meta_value as city,
      um_address_state.meta_value as state,
      um_company.meta_value as company,
      um_email.meta_value as billing_email
    FROM wp_woocommerce_order_itemmeta a
      LEFT JOIN wp_woocommerce_order_items b on a.order_item_id = b.order_item_id
      LEFT JOIN wp_postmeta customer_meta on customer_meta.post_id = b.order_id AND customer_meta.meta_key = '_customer_user'
      LEFT JOIN wp_users u on u.ID = customer_meta.meta_value
      LEFT JOIN wp_woocommerce_order_itemmeta qty_table on qty_table.order_item_id = b.order_item_id and qty_table.meta_key = '_qty'
      LEFT JOIN wp_usermeta um_last_name on u.ID = um_last_name.user_id and um_last_name.meta_key = 'last_name'
      LEFT JOIN wp_usermeta um_first_name on u.ID = um_first_name.user_id and um_first_name.meta_key = 'first_name'
      LEFT JOIN wp_usermeta um_address1 on u.ID = um_address1.user_id and um_address1.meta_key = 'billing_address_1'
      LEFT JOIN wp_usermeta um_address2 on u.ID = um_address2.user_id and um_address2.meta_key = 'billing_address_2'
      LEFT JOIN wp_usermeta um_address_city on u.ID = um_address_city.user_id and um_address_city.meta_key = 'billing_city'
      LEFT JOIN wp_usermeta um_address_state on u.ID = um_address_state.user_id and um_address_state.meta_key = 'billing_state'
      LEFT JOIN wp_usermeta um_email on u.ID = um_email.user_id and um_email.meta_key = 'billing_email'
      LEFT JOIN wp_usermeta um_company on u.ID = um_company.user_id and um_company.meta_key = 'billing_company'
    WHERE
      a.meta_key = '_product_id' AND a.meta_value = PRODUCT_ID
    

    【讨论】:

      猜你喜欢
      • 2018-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 2012-04-27
      相关资源
      最近更新 更多