我有一个用户表,有大约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万条记录。但实际上没有可用于限制用户数量的索引。 或者也许我错过了什么?
答案 0 :(得分: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
如果我没有建议改变你的逻辑。创建"发送"表,并在需要发送电子邮件时填写。在发送新电子邮件时从中删除(并添加到日志表中)。
答案 1 :(得分:0)
invisal,这不起作用,因为我们发送了不同的新闻简报 不同的时代。所以我需要为每个广告系列添加一个新字段 我们要去做
那就像@Denis建议的那样。您不需要为每个不同的简报创建新表。这是模拟模式:
contacts (contact_id, ...) newsletter_campaign (campaign_id, campaign_name) newsletter_sending (campaign_id, contact_id) newsletter_log (campaign_id, contact_id, send_date)
制作新广告系列
INSERT INTO newsletter_sending SELECT {$new_campaign_id}, contact_id
FROM contacts;
。向联系人发送简报
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}
我坚持要求您更改的原因是您当前的架构无法扩展。当联系和日志变得越来越大时,它会越来越慢