1M记录数据库查询优化

时间:2013-06-09 07:23:42

标签: mysql

我有一个用户表,有大约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万条记录。但实际上没有可用于限制用户数量的索引。 或者也许我错过了什么?

2 个答案:

答案 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)

制作新广告系列

  • 使用单个查询将所有联系人插入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}

我坚持要求您更改的原因是您当前的架构无法扩展。当联系和日志变得越来越大时,它会越来越慢