1

我有一张用户表,其中包含大约 100 万条“联系人”记录。我们将我们发送的电子邮件记录在另一个表“log_sent”中,该表也有大约 1M 条记录。

我们需要找出哪些用户还没有收到我们的时事通讯。所以我使用以下查询来获取我们需要发送给的下一个用户:

SELECT contact.* 
FROM contacts AS contact
LEFT JOIN log_sent AS sent ON sent.contact_id = contact.id
WHERE sent.id IS NULL 
LIMIT 0 , 1

这是 EXPLAIN 查询返回的内容:

id | select_type | table   | type | possible_keys | key        | key_len | ref                        | rows    | Extra
  1 | SIMPLE      | contact | ALL  | NULL          | NULL       | NULL    | NULL                       | 1031628 | 
1 | SIMPLE      | sent    | ref  | contact_id    | contact_id | 4       | admin_marketing.contact.id | 1       | Using where; Not exists

log_sent 表已建立contact_id索引。联系人表id作为主索引

此查询大约需要1.8几秒钟才能执行。而且 log_sent 表正在增长,所以这将是有问题的。如何优化此查询。

据我了解,查询似乎是搜索联系人表中的所有 100 万条记录。但是我真的没有索引可以用来限制使用的用户数量。或者也许我错过了什么?

4

2 回答 2

1

如果您真的只需要一行,重写查询以使其使用not exists子句可能会有所不同:

SELECT contact.* 
FROM contacts AS contact
WHERE NOT EXISTS ( SELECT 1 FROM log_sent AS sent WHERE sent.contact_id = contact.id )
LIMIT 1

如果不是,我建议您颠倒您的逻辑。创建一个“发送”表,并在需要发送电子邮件时填写。在您发送新电子邮件时从中删除(并添加到您的日志表中)。

于 2013-06-09T08:06:52.747 回答
0

invisal,这是行不通的,因为我们在不同的时间发送不同的时事通讯。所以我需要为我们要做的每个活动添加一个新字段

然后按照@Denis 的建议去做。您不需要为每个不同的时事通讯创建新表。这是模型模式:

联系人(contact_id,...)
newsletter_campaign(campaign_id,campaign_name)
newsletter_sending(campaign_id,contact_id)
newsletter_log(campaign_id、contact_id、send_date)

创建新广告系列

  • 使用单个查询将所有联系人插入 newsletter_sending:
  • INSERT INTO newsletter_sending SELECT {$new_campaign_id}, contact_id FROM contacts;.

向联系人发送时事通讯

  • 从 newsletter_sending 列表中删除联系人并添加到日志
  • DELETE FROM newsletter_sending WHERE campaign_id = {$campaign_id} AND contact_id = {$contact_id}
  • INSERT INTO newsletter_log VALUES({$campaign_id, {$contact_id}, NOW())

查询未收到您的时事通讯的用户

  • SELECT * FROM newsletter_sending WHERE campaign_id = {$campaign_id}

查询已收到您的时事通讯的用户

  • SELECT * FROM newsletter_log WHERE campaign_id = {$campaign_id}

我坚持让您更改的原因是您当前的模式无法扩展。当联系人和日志越来越大时,它会越来越慢

于 2013-06-09T07:32:54.260 回答