我们要实现的目标:
基本上,我们正在收集一些关于用户(姓名、地址)的一对一元数据,然后我们正在对他们的订单进行一些汇总报告。
查询 1
SELECT
-- STUDENT DATA
wp_users.user_email AS 'email',
-- STUDENT METADATA
um_fn.meta_value AS 'first_name',
um_ln.meta_value AS 'last_name',
### MANY MORE ###
-- ORDER DATA
MAX(pmt_orders.order_date) last_order,
MIN(pmt_orders.order_date) first_order,
COUNT(pmt_order_course.fk_order_id) life_courses,
### MANY MORE AGGREGATE FUNCTIONS ###
FROM wp_users
### LEFT OUTER JOINS, INNER JOINS, LEFT JOINS (FOR THE AGGREGATE FUNCTIONS) ###
-- STUDENT METADATA
LEFT JOIN wp_usermeta um_fn ON wp_users.id = um_fn.user_id AND um_fn.meta_key = 'shipping_first_name'
LEFT JOIN wp_usermeta um_ln ON wp_users.id = um_ln.user_id AND um_ln.meta_key = 'shipping_last_name'
### MANY MORE ###
WHERE pmt_order_course.unenroll_date IS NULL OR pmt_order_course.unenroll_date = '0000-00-00'
GROUP BY wp_users.user_email
时间:13 秒
我们开始调查,我将其分解为一个元数据查询(0.5 秒)和其他内容(2 秒)。基本上只是将列拆分为两个单独的查询。
注意:我确实尝试将每个非聚合选择添加到 GROUP BY
中,以便我们符合严格模式。对性能零影响。
查询 2
很困惑,然后我们把它变回一个大查询。该方法是将非聚合选择移动到外部选择。
SELECT users.*,
-- STUDENT METADATA
um_fn.meta_value AS 'first_name',
um_ln.meta_value AS 'last_name',
### MANY MORE ###
FROM (
SELECT
-- STUDENT DATA
wp_users.ID,
wp_users.user_email AS 'email',
-- ORDER DATA
MAX(pmt_orders.order_date) last_order,
MIN(pmt_orders.order_date) first_order,
COUNT(pmt_order_course.fk_order_id) life_courses,
### MANY MORE AGGREGATE FUNCTIONS ###
FROM wp_users
### LEFT OUTER JOINS, INNER JOINS, LEFT JOINS (FOR THE AGGREGATE FUNCTIONS) ###
WHERE pmt_order_course.unenroll_date IS NULL OR pmt_order_course.unenroll_date = '0000-00-00'
GROUP BY wp_users.user_email
) AS users
-- STUDENT METADATA
LEFT JOIN wp_usermeta um_fn ON users.id = um_fn.user_id AND um_fn.meta_key = 'shipping_first_name'
LEFT JOIN wp_usermeta um_ln ON users.id = um_ln.user_id AND um_ln.meta_key = 'shipping_last_name'
### MANY MORE ###
时间:2 秒
结果
查询 2 产生相同的结果,并且在数学上等同于查询 1。它在 2 秒内运行。
我能理解为什么,MySQL 是为每个订单查找一次元数据,然后按用户汇总,而不是为每个用户查找一次元数据。
一些分析数据:wp_users
表很大,聚合行大约是每个用户两行。
问题
为什么 MySQL 优化器不能自己解决这个问题?有没有另一种方法可以编写看起来更具表现力的查询(如查询 1),同时使 MySQL 使用查询 2 的更快执行路径?
最佳答案
我要说的是,请记住,在查询 1 中,您在用户表上加入了其余未聚合查询记录的次数。
然而,在查询 2 中,您只是加入聚合数据的次数。
这就是它与众不同的原因。
如果你只需要名字和姓氏,我想你可以做一个子查询来获取名字和姓氏而不是 um_fn.meta_value,但是如果选项 2 很快,你最好离开它单独(或添加没有人会阅读的评论)。尽管在查询 1 中尝试了一些可能更具可读性的东西?
(SELECT um_fn.meta_value FROM wp_usermeta um_fn ON wp_users.id = um_fn.user_id AND um_fn.meta_key = 'shipping_first_name') as 'first_name',
(SELECT um_ln.meta_value FROM wp_usermeta um_ln ON wp_users.id = um_ln.user_id AND um_ln.meta_key = 'shipping_last_name') as 'last_name',
关于MySQL GROUP BY 使用 JOIN 时速度较慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48122118/