我有以下查询可获取订单数据,工作正常,但需要13.63秒:
SELECT
( SELECT meta_value FROM `myprefix_postmeta` as postmeta WHERE postmeta.meta_key = '_sku' AND postmeta.post_id = woocommerce_order_itemmeta3.meta_value ) AS sku,
woocommerce_order_items.order_item_name AS title,
SUM( woocommerce_order_itemmeta.meta_value ) AS quantity,
SUM( woocommerce_order_itemmeta2.meta_value ) AS total
FROM `myprefix_woocommerce_order_items` AS woocommerce_order_items
LEFT JOIN `myprefix_posts` AS posts ON posts.ID = woocommerce_order_items.order_id
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS woocommerce_order_itemmeta ON woocommerce_order_itemmeta.order_item_id = woocommerce_order_items.order_item_id
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS woocommerce_order_itemmeta2 ON woocommerce_order_itemmeta2.order_item_id = woocommerce_order_items.order_item_id
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS woocommerce_order_itemmeta3 ON woocommerce_order_itemmeta3.order_item_id = woocommerce_order_items.order_item_id
WHERE posts.post_type = 'shop_order'
AND posts.post_status IN( 'wc-completed', 'wc-processing', 'wc-on-hold' )
AND woocommerce_order_itemmeta.meta_key = '_qty'
AND woocommerce_order_itemmeta2.meta_key = '_line_total'
AND woocommerce_order_itemmeta3.meta_key = '_product_id'
GROUP BY woocommerce_order_itemmeta3.meta_value
ORDER BY total DESC
我想优化此查询以使其运行更快。
也许只是需要很长时间才能返回。但是,无论如何,我都试图删除上面的子查询,结果如下:
SELECT
postmeta.meta_value AS sku,
woocommerce_order_items.order_item_name AS title,
SUM( woocommerce_order_itemmeta.meta_value ) AS quantity,
SUM( woocommerce_order_itemmeta2.meta_value ) AS total
FROM `myprefix_woocommerce_order_items` AS woocommerce_order_items
LEFT JOIN `myprefix_posts` AS posts ON posts.ID = woocommerce_order_items.order_id
LEFT JOIN `myprefix_postmeta` AS postmeta ON posts.ID = woocommerce_order_items.order_id
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS woocommerce_order_itemmeta ON woocommerce_order_itemmeta.order_item_id = woocommerce_order_items.order_item_id
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS woocommerce_order_itemmeta2 ON woocommerce_order_itemmeta2.order_item_id = woocommerce_order_items.order_item_id
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS woocommerce_order_itemmeta3 ON woocommerce_order_itemmeta3.order_item_id = woocommerce_order_items.order_item_id
WHERE posts.post_type = 'shop_order'
AND posts.post_status IN( 'wc-completed', 'wc-processing', 'wc-on-hold' )
AND postmeta.meta_key = '_sku'
AND postmeta.post_id = woocommerce_order_itemmeta3.meta_value
AND woocommerce_order_itemmeta.meta_key = '_qty'
AND woocommerce_order_itemmeta2.meta_key = '_line_total'
AND woocommerce_order_itemmeta3.meta_key = '_product_id'
GROUP BY woocommerce_order_itemmeta3.meta_value
ORDER BY total DESC
这快几毫秒,但是有什么方法可以进一步优化吗?
非常感谢您可能需要了解这些表背后的数据,它们是标准的WordPress database tables和WooCommerce Database Schema,我无法真正共享这些表背后的数据。
上面的第二个示例存在一个附带问题,即如果SKU为NULL,则不包含该行,而最上面的一个包含该行,因此目前仍然是首选查询。
更新#1
基于答案:https://stackoverflow.com/a/54202562/8369600
我最初从答案的第1部分更新了我的代码格式,并且效果很好。
然后我在步骤2中使用了代码,并对格式进行了一些细微更改,以便在phpMyAdmin中为我工作,这些更改是:
SELECT
(SELECT meta_value
FROM `myprefix_postmeta` as postmeta
WHERE
postmeta.meta_key = '_sku'
AND postmeta.post_id = ( -- Substitute meta_value with CASE-expressions
CASE
WHEN IM.meta_key = '_product_id' THEN IM.meta_value
ELSE NULL
END
) -- IM3.meta_value
) AS sku,
-- think above is okay ^^^^
I.order_item_name AS title,
SUM(
CASE -- Substitute meta_value with CASE-expressions
WHEN IM.meta_key = '_qty' THEN IM.meta_value
ELSE 0
END
) AS quantity,
-- IM2.meta_value ) AS total
SUM( -- Substitute meta_value with CASE-expressions
CASE
WHEN IM.meta_key = '_line_total' THEN IM.meta_value
ELSE 0
END
) AS total
FROM
`myprefix_woocommerce_order_items` AS I
LEFT JOIN `myprefix_posts` AS posts
ON posts.ID = I.order_id
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM -- Make readable aliases
ON IM.order_item_id = I.order_item_id
AND IM.meta_key IN('_qty', '_line_total', '_product_id')
-- AND IM.meta_key = '_qty' -- Move predicates from WHERE
-- LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM2
-- ON IM2.order_item_id = I.order_item_id
-- AND IM2.meta_key = '_line_total' -- Move predicates from WHERE
-- LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM3
-- ON IM3.order_item_id = I.order_item_id
-- AND IM3.meta_key = '_product_id' -- Move predicates from WHERE
WHERE
posts.post_type = 'shop_order'
AND posts.post_status IN
( 'wc-completed', 'wc-processing', 'wc-on-hold' )
GROUP BY
(
CASE
WHEN IM.meta_key = '_product_id' THEN IM.meta_value
ELSE NULL
END
) -- IM3.meta_value
ORDER BY
total DESC
但是这返回:
在所有行都填充有数据之前,请怀疑这些案例是否与原始案例不符。
请注意,我还按照前面的注释之一的要求,添加了指向WooCommerce数据库文档的链接。
答案 0 :(得分:2)
meta_key
谓词移至JOIN
s 为了清楚起见,我采取了自由格式化您的查询的方式。
我重命名了别名,并将meta_key
谓词从WHERE
移到JOIN
s:
SELECT
(SELECT meta_value
FROM `myprefix_postmeta` as postmeta
WHERE
postmeta.meta_key = '_sku'
AND postmeta.post_id = IM3.meta_value ) AS sku,
I.order_item_name AS title,
SUM (IM.meta_value ) AS quantity,
SUM (IM2.meta_value ) AS total
FROM
`myprefix_woocommerce_order_items` AS I
LEFT JOIN `myprefix_posts` AS posts
ON posts.ID = I.order_id
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM -- Make readable aliases
ON IM.order_item_id = I.order_item_id
AND IM.meta_key = '_qty' -- Move predicates from WHERE
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM2
ON IM2.order_item_id = I.order_item_id
AND IM2.meta_key = '_line_total' -- Move predicates from WHERE
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM3
ON IM3.order_item_id = I.order_item_id
AND IM3.meta_key = '_product_id' -- Move predicates from WHERE
WHERE
posts.post_type = 'shop_order'
AND posts.post_status IN
( 'wc-completed', 'wc-processing', 'wc-on-hold' )
GROUP BY
IM3.meta_value
ORDER BY
total DESC
现在,我们有了绝对等效的查询。
让我们看看我们可以做些什么。
LEFT JOIN
的3个myprefix_woocommerce_order_itemmeta
至IM.order_item_id = I.order_item_id
看起来不必要的重复meta_key
上有不同的谓词所以我们可以:
a。用一个JOIN替换3个JOIN
b。用CASE表达式替换IM / IM2 / IM3字段
SELECT
(SELECT meta_value
FROM `myprefix_postmeta` as postmeta
WHERE
postmeta.meta_key = '_sku'
AND postmeta.post_id = ( -- Substitute meta_value with CASE-expressions
CASE
WHEN IM.meta_key = '_product_id' THEN IM.meta_value
ELSE NULL
END
) -- IM3.meta_value
) AS sku,
I.order_item_name AS title,
SUM (
CASE -- Substitute meta_value with CASE-expressions
WHEN IM.meta_key = '_qty' THEN IM.meta_value
ELSE 0
END
) AS quantity
-- IM2.meta_value ) AS total
SUM ( -- Substitute meta_value with CASE-expressions
CASE
WHEN IM.meta_key = '_line_total' THEN IM.meta_value
ELSE 0
END
) AS total
FROM
`myprefix_woocommerce_order_items` AS I
LEFT JOIN `myprefix_posts` AS posts
ON posts.ID = I.order_id
LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM -- Make readable aliases
ON IM.order_item_id = I.order_item_id
AND IM.meta_key IN ('_qty', '_line_total', '_product_id')
-- AND IM.meta_key = '_qty' -- Move predicates from WHERE
-- LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM2
-- ON IM2.order_item_id = I.order_item_id
-- AND IM2.meta_key = '_line_total' -- Move predicates from WHERE
-- LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM3
-- ON IM3.order_item_id = I.order_item_id
-- AND IM3.meta_key = '_product_id' -- Move predicates from WHERE
WHERE
posts.post_type = 'shop_order'
AND posts.post_status IN
( 'wc-completed', 'wc-processing', 'wc-on-hold' )
GROUP BY
(
CASE
WHEN IM.meta_key = '_product_id' THEN IM.meta_value
ELSE NULL
END
) -- IM3.meta_value
ORDER BY
total DESC
写没有数据的SQL不太舒服。
对于每个版本的mysql,此查询可能都不正确。
因此,请尝试理解原理,而不仅仅是复制粘贴我的代码。
将结果或问题通知我们。
答案 1 :(得分:1)
如果woocommerce是WordPress的分支,则他们可能在索引myprefix_woocommerce_order_itemmeta
方面做得很差。调整here中的技巧以提高性能。
我同意其他人-EAV模式模式很糟糕。我上面的索引建议对 some 有帮助。
例如,“ order”始终具有数量,product_id,line_total;那么,为什么不将它们作为真实的列而不是将它们隐藏在另一个表中,就好像它们是稀有属性一样呢?对于只有一些商品具有“衣着尺寸”或“ F-stop”或“传输类型”的购物网站,EAV有点必要。 (在这种情况下,JSON 可能比EAV更好。)
架构审核
好,woocommerce比WP(reference)差:
CREATE TABLE {$wpdb->prefix}woocommerce_order_itemmeta (
meta_id BIGINT UNSIGNED NOT NULL auto_increment,
order_item_id BIGINT UNSIGNED NOT NULL,
meta_key varchar(255) default NULL,
meta_value longtext NULL,
PRIMARY KEY (meta_id),
KEY order_item_id (order_item_id),
KEY meta_key (meta_key(32))
) $collate;
前缀索引(meta_key(32)
)很少有用,并且通常适得其反。尽管如此,可能我所有的建议(请参见上面的链接)都适用,并且名称进行了适当的更改。
答案 2 :(得分:0)
要做的第一件事是检查在LEFT JOIN和过滤位置的所有列上是否有正确的索引。通常,缺少索引是导致查询缓慢的原因。
如果您想走得更远,我将重建索引。也许一些碎片也使事情变慢了。
尽管不是必需的,您也可以尝试将已完成wc,进行wc处理的迁移键制作到自己的表中,并通过INT进行联接。
您还可以尝试规范化SUM甚至为它们创建一个计算列。