消除一个表与另一个表的值。超慢

时间:2011-10-20 00:01:52

标签: mysql sql

在同一个数据库中,我有一个表messages,其中包括:idtitletext我想要的列。我只想要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秒)

2 个答案:

答案 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上添加一个索引。然后尝试再次运行查询并测试性能。