在同一个数据库中,我有一个表messages
,其中包括:id
,title
,text
我想要的列。我只想要title
在表lastlogon
中没有条目的记录,其标题等同于username
。
我一直在PHP中使用这个SQL命令,通常需要2-3秒才能启动:
SELECT DISTINCT * FROM messages WHERE title NOT IN (SELECT username FROM lastlogon) LIMIT 1000
在表lastlogon
开始拥有约80%的值表messages
之前,这一切都很好。消息有大约8000个条目,lastlogon大约7000个。现在它需要大约一分钟到2分钟才能完成。 MySQL可以实现非常高的CPU使用率。
我尝试了以下但没有运气减少时间:
SELECT id,title,text FROM messages a LEFT OUTER JOIN lastlogon b ON (a.title = b.username) LIMIT 1000
为什么突然间这么少的条目需要这么长时间?我尝试多次重启mysql和apache。我正在使用debian linux。
编辑:这是结构
--
-- Table structure for table `lastlogon`
--
CREATE TABLE IF NOT EXISTS `lastlogon` (
`username` varchar(25) NOT NULL,
`lastlogon` date NOT NULL,
`datechecked` date NOT NULL,
PRIMARY KEY (`username`),
KEY `username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- --------------------------------------------------------
--
-- Table structure for table `messages`
--
CREATE TABLE IF NOT EXISTS `messages` (
`id` smallint(9) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`email` varchar(50) NOT NULL,
`text` mediumtext,
`folder` tinyint(2) NOT NULL,
`read` smallint(5) unsigned NOT NULL,
`dateline` int(10) unsigned NOT NULL,
`ip` varchar(15) NOT NULL,
`attachment` varchar(255) NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`username` varchar(300) NOT NULL,
`error` varchar(500) NOT NULL,
PRIMARY KEY (`id`),
KEY `title` (`title`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=9010 ;
编辑2
使用新索引编辑结构。 在messages.title和lastlogon.username上都放了一个索引后,我想出了这些结果:
显示0到29行(总共623,查询花了74.4938秒)
答案 0 :(得分:1)
首先:使用标题+ id
上的复合键替换标题上的键ALTER TABLE messages DROP INDEX title;
ALTER TABLE messages ADD INDEX title (title, id);
现在将选择更改为:
SELECT m.* FROM messages m
LEFT JOIN lastlogon l ON (l.username = m.title)
WHERE l.username IS NULL
-- GROUP BY m.id DESC -- faster replacement for distinct. I don't think you need this.
LIMIT 1000;
或者
SELECT m.* FROM messages m
WHERE m.title NOT IN (SELECT l.username FROM lastlogon l)
-- GROUP BY m.id DESC -- faster than distinct, I don't think you need it though.
LIMIT 1000;
缓慢的另一个问题是SELECT m.*
部分
通过选择所有列,您将迫使MySQL进行额外的工作
只选择您需要的列:
SELECT m.title, m.name, m.email, ......
这也将加快查询速度。
您可以使用另一种技巧:
用截止日期替换限制1000。
步骤1:在时间戳(或要用于截止的任何字段)上添加索引。
SELECT m.* FROM messages m
LEFT JOIN lastlogon l ON (l.username = m.title)
WHERE (m.id > (SELECT MIN(M2.ID) FROM messages m2 WHERE m2.timestamp >= '2011-09-01'))
AND l.username IS NULL
-- GROUP BY m.id DESC -- faster replacement for distinct. I don't think you need this.
答案 1 :(得分:0)
我建议你在messages.title
上添加一个索引。然后尝试再次运行查询并测试性能。