以下查询有效,但随着sendlog表的大小随时间增加而变慢。目标是从newsletter_subscribers表中选择所有订户的列表,其中不在newsletter_sendlog表中具有给定简报id的电子邮件条目。目前,我的mysql服务器上大约需要2.2秒,而sendlog中只有几千个条目。
SELECT `newsletter_subscribers`.*
FROM `newsletter_subscribers`
INNER JOIN `newsletter_to_subscriber`
ON newsletter_to_subscriber.subscriber_id = newsletter_subscribers.id
LEFT JOIN (
SELECT `newsletter_sendlog`.`subscriber_email`
FROM `newsletter_sendlog`
WHERE (newsletter_id='7')
) AS `sendlog`
ON newsletter_subscribers.email = sendlog.subscriber_email
WHERE (sendlog.subscriber_email IS NULL)
AND (newsletter_to_subscriber.newsletter_id = '7')
EXPLAIN(查询)输出以下内容:
我对EXPLAIN的输出不太熟悉,但是如果我正确读取它会表明它没有使用我在newsletter_sendlog.subscriber_email上定义的索引。我尝试在该表上使用USE INDEX(电子邮件),但它似乎没有生效。
有关如何优化此功能的任何建议?或者可能建议另一个查询做同样的事情?
newsletter_sendlog的创建表:
CREATE TABLE `newsletter_sendlog` (
`id` int(11) unsigned NOT NULL auto_increment,
`subscriber_email` varchar(100) NOT NULL default '',
`newsletter_id` int(11) default NULL,
`sendstatus` int(11) default NULL,
`senddate` timestamp NOT NULL default CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `newsletter_id` (`newsletter_id`),
KEY `email` (`subscriber_email`)
) ENGINE=MyISAM AUTO_INCREMENT=2933 DEFAULT CHARSET=latin1;
为newsletter_subscribers创建表:
CREATE TABLE `newsletter_subscribers` (
`id` int(11) unsigned NOT NULL auto_increment,
`email` varchar(100) NOT NULL default '',
`name` tinytext,
PRIMARY KEY (`id`),
KEY `email` (`email`)
) ENGINE=MyISAM AUTO_INCREMENT=2964 DEFAULT CHARSET=utf8;
为newsletter_to_subscriber创建表:
CREATE TABLE `newsletter_to_subscriber` (
`id` int(11) unsigned NOT NULL auto_increment,
`newsletter_id` int(11) NOT NULL,
`subscriber_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `newsletter_subscriber` (`newsletter_id`,`subscriber_id`)
) ENGINE=MyISAM AUTO_INCREMENT=2964 DEFAULT CHARSET=latin1;
在subscriber_id上添加索引后,为newsletter_to_subscriber创建表现在看起来像这样:
CREATE TABLE `newsletter_to_subscriber` (
`id` int(11) unsigned NOT NULL auto_increment,
`newsletter_id` int(11) NOT NULL,
`subscriber_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `newsletter_subscriber` (`newsletter_id`,`subscriber_id`),
KEY `subscriber` (`subscriber_id`)
) ENGINE=MyISAM AUTO_INCREMENT=2964 DEFAULT CHARSET=latin1;
@nobody:
建议的查询说明
答案 0 :(得分:1)
最好选择特定的字段,而不是星号(*),并避免反引号(`)。尝试查看以下(重写)查询是否更有效:
SELECT
newsletter_subscribers.id,
newsletter_subscribers.email,
newsletter_subscribers.name
FROM
newsletter_subscribers
LEFT JOIN
newsletter_to_subscriber
ON
newsletter_to_subscriber.subscriber_id = newsletter_subscribers.id
LEFT JOIN
newsletter_sendlog
ON
newsletter_subscribers.email = newsletter_sendlog.subscriber_email
WHERE
newsletter_to_subscriber.newsletter_id = 7
AND
newsletter_sendlog.newsletter_id = 7
AND
newsletter_sendlog.subscriber_email IS NULL
答案 1 :(得分:0)
SELECT `newsletter_subscribers`.* FROM `newsletter_subscribers`
INNER JOIN `newsletter_to_subscriber`
ON newsletter_to_subscriber.subscriber_id = newsletter_subscribers.id
LEFT JOIN (
SELECT `newsletter_sendlog`.`subscriber_email` FROM `newsletter_sendlog`
WHERE (newsletter_id='7')) AS `sendlog`
ON newsletter_subscribers.email=sendlog.subscriber_email
WHERE (sendlog.subscriber_email IS NULL)
AND (newsletter_to_subscriber.newsletter_id = '7')
您可以尝试在单列newsletter_to_subscriber.subscriber_id
看看它是否有帮助?
尝试使用如下表格结构:
CREATE TABLE `newsletter_to_subscriber` (
`id` int(11) unsigned NOT NULL auto_increment,
`newsletter_id` int(11) NOT NULL,
`subscriber_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `newsletter_subscriber` (`newsletter_id`,`subscriber_id`)
KEY `subscriber_id_key` (`subscriber_id`)
KEY `newsletter_id_key` (`newsletter_id`)
) ENGINE=MyISAM AUTO_INCREMENT=2964 DEFAULT CHARSET=latin1;
答案 2 :(得分:0)
不完全确定,但我认为索引被忽略,因为你正在寻找NULL值。
虽然有一种不同的,希望更有效的方式来运行此查询:
select *
from newsletter_subscribers
where email not in
(select subscriber_email
from newsletter_sendlog
where newsletter_id='7')
答案 3 :(得分:0)
首先,您不需要该子查询:
SELECT `newsletter_subscribers`.*
FROM `newsletter_subscribers`
INNER JOIN `newsletter_to_subscriber`
ON( newsletter_to_subscriber.subscriber_id = newsletter_subscribers.id )
LEFT JOIN `newsletter_sendlog`
ON( newsletter_subscribers.email = newsletter_sendlog.subscriber_email AND
newsletter_sendlog.newsletter_id = '7' )
WHERE newsletter_sendlog.subscriber_email IS NULL
上面的查询将完成这项工作。
其次在newsletter_to_subscriber
中,您在newsletter_id
和subscriber_id
上有一个多部分索引,您的查询无法使用该索引,因为它将搜索subscriber_id
和在索引中排在第二位,你需要在subscriber_id
上有一个单独的索引:
INDEX( subscriber_id )