2009-05-30 41 views
5

好的,这里是一个查询,我现在正在一个拥有45,000条记录并且大小为65MB的表上运行......并且正在变得越来越大(所以我必须考虑未来的表现,以及在这里)的:在mySQL中优化嵌入式SELECT查询

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不是空的(因为它只填充已完成的付款),以及(嵌入式选择)成员从未拥有过“com完成“付款 - 这意味着他是一个新成员(仅仅是因为系统确实会重新投入,而且这是区分刚刚获得回扣的现有成员和第一次收到新成员的新成员之间唯一的区别) 。

现在,是否有任何可能的方式来优化此查询使用更少的资源或什么,并停止采取我的MySQL资源跪下......?

我是否缺少任何信息以进一步澄清此问题?让我知道...

编辑:

这里有指标已经在该表:

PRIMARY PRIMARY 46757 payment_id

member_id INDEX 23378 member_id

payer_id INDEX 11689 payer_id

coupon_id INDEX 1 coupon_id

tm_added INDEX 46757 tm_added,PRODUCT_ID

tm_completed INDEX 46757 tm_completed,PRODUCT_ID

+0

你对其中正在使用搜索ARGS领域指标 – James 2009-05-30 05:20:06

回答

7

像这样的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'); 

为由您BETWEEN条件所暗示的支票“tm_completed IS NOT NULL”是没有必要的。

另外,还要确保你有一个索引:使用与子查询

(tm_completed, completed) 
+0

打我?到冲床; +1为速度 – 2009-05-30 05:25:10

+0

哇...不知道这只是我已经做出的一些小改动,只是将“IN”替换为“EXISTS”..​​....谢谢! – 2009-05-30 15:30:01

2

避免; MySQL不优化这些好(虽然有5.4和6.0未决优化对此(见here),改写本作为联接可能会得到你的性能提升。

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 

其次,我将不得不看你的表模式,您使用的指标

7

我很开心组建这个解决方案,它不需要子查询:

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;