优化 mySQL 中的嵌入式 SELECT 查询
-
06-09-2019 - |
题
好的,这是我现在在一个有 45,000 条记录、大小为 65MB 的表上运行的查询...并且即将变得越来越大(所以我也必须在这里考虑未来的表现):
SELECT count(payment_id) as signup_count, sum(amount) as signup_amount
FROM payments p
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND completed > 0
AND tm_completed IS NOT NULL
AND member_id NOT IN (SELECT p2.member_id FROM payments p2 WHERE p2.completed=1 AND p2.tm_completed < '2009-05-01' AND p2.tm_completed IS NOT NULL GROUP BY p2.member_id)
正如你可能想象或可能想象不到的那样——它使 mysql 服务器陷入瘫痪......
它的作用是 - 它只是提取注册的新用户数量,至少有一笔“已完成”付款,tm_completed 不为空(因为它只填充已完成的付款),并且(嵌入的 Select)该成员已以前从未有过“完成”付款 - 这意味着他是新会员(只是因为系统会重新计费等,这是区分刚刚重新计费的现有会员和已计费的新会员的唯一方法第一次)。
现在,有没有可能的方法来优化这个查询以使用更少的资源或其他东西,并停止占用我的 mysql 资源......?
我是否缺少任何信息来进一步澄清这一点?让我知道...
编辑:
以下是该表上已有的索引:
主要 主要 46757 payment_id
会员 ID 索引 23378 会员 ID
payer_id 索引 11689 payer_id
coupon_id 索引 1 coupon_id
tm_added 索引 46757 tm_added,product_id
tm_completed 索引 46757 tm_completed,product_id
解决方案
这些种IN
子查询的是在MySQL有点慢。我想改写这样的:
SELECT COUNT(1) AS signup_count, SUM(amount) AS signup_amount
FROM payments p
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND completed > 0
AND NOT EXISTS (
SELECT member_id
FROM payments
WHERE member_id = p.member_id
AND completed = 1
AND tm_completed < '2009-05-01');
如由您tm_completed IS NOT NULL
条件暗示支票“BETWEEN
”是不必要的。
另外,还要确保你有一个索引:
(tm_completed, completed)
其他提示
我的乐趣放在一起这溶液,其不需要的子查询:
SELECT count(p1.payment_id) as signup_count,
sum(p1.amount) as signup_amount
FROM payments p1
LEFT JOIN payments p2
ON p1.member_id = p2.member_id
AND p2.completed = 1
AND p2.tm_completed < date '2009-05-01'
WHERE p1.completed > 0
AND p1.tm_completed between date '2009-05-01' and date '2009-05-30'
AND p2.member_id IS NULL;
避免将 IN 与子查询一起使用;MySQL 没有很好地优化这些(尽管在 5.4 和 6.0 中对此有待优化(请参阅 这里)。将其重写为连接可能会提高性能:
SELECT count(payment_id) as signup_count, sum(amount) as signup_amount
FROM payments p
LEFT JOIN (SELECT p2.member_id
FROM payments p2
WHERE p2.completed=1
AND p2.tm_completed < '2009-05-01'
AND p2.tm_completed IS NOT NULL
GROUP BY p2.member_id) foo
ON p.member_id = foo.member_id AND foo.member_id IS NULL
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND completed > 0
AND tm_completed IS NOT NULL
其次,我必须查看您的表架构;你在使用索引吗?