返回大结果的组合SQL查询

时间:2013-03-08 00:41:05

标签: mysql sql performance join

我要求从mysql数据库收集数据,以便我们能够向在给定天数内没有活动的客户发送促销电子邮件,但只向那些从未在我们这里注册过促销点的客户发送。数据库相当大,超过50,000个客户,并且检查那些没有注册点的客户的查询需要一个多小时来单独处理。 所以我认为,如果我将其缩小到在给定时间内没有登录的客户,然后仅对那些customer_id进行搜索,那么它会更快。但是,我尝试组合这两个查询是完全失败,返回“操作数应该包含1列”错误。

考虑到我需要在查询中收到的数据,是否可以实现。

首先需要1小时的查询:

SELECT c.customers_id
FROM customers c 
LEFT JOIN codes_redeem_history pc 
ON pc.customer_id=c.customers_id
WHERE pc.customer_id IS NULL

在给定时间内对客户进行第二次查询:

SELECT ci.customers_info_date_of_last_logon, ci.customers_info_id, c.customers_email_address, c.customers_lastname, c.customers_firstname 
FROM customers c, customers_info ci 
WHERE c.customers_id = ci.customers_info_id 
GROUP BY c.customers_email_address 
HAVING max(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY) 
ORDER BY c.customers_lastname, c.customers_firstname ASC

我是如何尝试的,未能将它们结合起来:

SELECT c.customers_id
FROM customers c 
LEFT JOIN codes_redeem_history pc 
ON pc.customer_id=c.customers_id
WHERE pc.customer_id IS NULL
AND c.customers_id
IN
(Select ci.customers_info_date_of_last_logon, ci.customers_info_id, c.customers_email_address, c.customers_lastname, c.customers_firstname 
FROM customers c, customers_info ci 
WHERE c.customers_id = ci.customers_info_id 
GROUP BY c.customers_email_address 
HAVING max(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY) 
ORDER BY c.customers_lastname, c.customers_firstname ASC)

我可以从错误消息中看到它不会在IN(SELECT)中允许这样复杂的查询 查询的一部分,但我不知道如何重新排列它,或者它是否可行。

您对SQL Gurus有何建议?

由于

在稍微改变要求之后,我可以对此提供更多帮助。

除了早先的回答之外,我还尝试稍微更改查询以允许选择时间跨度,而不是在30天时修复。我使用了HAVING MAX(ci.customers_info_date_of_last_logon)&gt; ='“。$ ndate。”',其中$ ndate是一个包含所需日期的var。显然它不起作用,因为日期与30天不一样。我似乎无法使用WHERE条件代替HAVING MAX。任何解决方案?

1 个答案:

答案 0 :(得分:2)

第一个查询需要很长时间才能完成的原因是,我几乎可以确定它,因为你缺少定义它们关系的列的索引,通过执行以下行来改变表,

ALTER TABLE codes_redeem_history ADD INDEX (customer_id);
ALTER TABLE customers ADD INDEX (customers_id);
ALTER TABLE customers_info ADD INDEX (customers_info_id);

完整查询,

SELECT  c.customers_id
FROM    customers c 
        LEFT JOIN codes_redeem_history pc 
        ON pc.customer_id=c.customers_id
        LEFT JOIN
        (
            Select  c.customers_id 
            FROM    customers c 
                    INNER JOIN customers_info ci
                        ON c.customers_id = ci.customers_info_id 
            GROUP   BY c.customers_email_address 
            HAVING  MAX(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY)
        ) d ON c.customers_id = d.customers_id
WHERE   pc.customer_id IS NULL AND 
        d.customers_id IS NOT NULL

更新1

SELECT  c.customers_id
FROM    customers c 
        INNER JOIN customers_info ci
            ON c.customers_id = ci.customers_info_id 
        LEFT JOIN codes_redeem_history pc 
            ON c.customers_id = pc.customer_id
WHERE   pc.customer_id IS NULL
GROUP   BY c.customers_email_address 
HAVING  MAX(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY)