0

我一直在开发一个小型 Perl 程序,该程序与文章表一起工作,如果尚未阅读,则将它们显示给用户。它一直运行良好,总体而言速度非常快。但是,今天下午,性能已经从足够快的速度下降,以至于我不担心将查询优化到每个查询 3-4 秒的冰期。为了选择文章,我提出了这个查询:

SELECT channelitem.ciid, channelitem.cid, name, description, url, creationdate, author
FROM  `channelitem` 
WHERE ciid NOT 
IN (

SELECT ciid
FROM  `uninet_channelitem_read` 
WHERE uid =  '1030'
)
AND (
cid =117
OR cid =308
OR cid =310
)
ORDER BY  `channelitem`.`creationdate` DESC 
LIMIT 0 , 100

可能的 cid 列表各不相同,可能更多。无论如何,我注意到进行查询的总时间中大约有 2-3 秒用于“ORDER BY”。如果我删除它,只需要大约半秒的时间就可以将查询返回给我。如果我放弃子查询,性能会恢复正常......但直到今天下午,在正常工作一周左右之后,子查询似乎没有问题。

有什么想法可能会减慢它的速度吗?我可以做些什么来尝试让性能恢复到鼻烟?被查询的表有 45,000 行。子查询的表目前少于 3,000 行。

更新:顺便说一句,如果有人对如何进行多个查询或其他一些更有效地完成我想要做的事情有建议,我会全神贯注。我现在真的很困惑如何解决这个问题。我可以在联接之前以某种方式应用 order by 以使其应用于真实表而不是派生表吗?这样会更有效率吗?

这是查询的最新版本,来自@Gordon 的建议,如下

SELECT channelitem.ciid, channelitem.cid, name, description, url, creationdate, author
FROM  `channelitem` 
LEFT JOIN (

SELECT ciid, dateRead
FROM  `uninet_channelitem_read` 
WHERE uid =  '1030'
)alreadyRead ON channelitem.ciid = alreadyRead.ciid
WHERE (
alreadyRead.ciid IS NULL
)
AND  `cid` 
IN ( 6648, 329, 323, 6654, 6647 ) 
ORDER BY  `channelitem`.`creationdate` DESC 
LIMIT 0 , 100

另外,我应该提到关于这两个表的数据库结构是什么样的——也许有人会发现这个结构的一些奇怪之处:

CREATE TABLE IF NOT EXISTS `channelitem` (
  `newsversion` int(11) NOT NULL DEFAULT '0',
  `cid` int(11) NOT NULL DEFAULT '0',
  `ciid` int(11) NOT NULL AUTO_INCREMENT,
  `description` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,
  `url` varchar(222) DEFAULT NULL,
  `creationdate` datetime DEFAULT NULL,
  `urgent` varchar(10) DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
  `lastchanged` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `author` varchar(255) NOT NULL,
  PRIMARY KEY (`ciid`),
  KEY `newsversion` (`newsversion`),
  KEY `cid` (`cid`),
  KEY `creationdate` (`creationdate`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1638554365 ;

CREATE TABLE IF NOT EXISTS `uninet_channelitem_read` (
  `ciid` int(11) NOT NULL,
  `uid` int(11) NOT NULL,
  `dateRead` datetime NOT NULL,
  PRIMARY KEY (`ciid`,`uid`),
  KEY `ciid` (`ciid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
4

2 回答 2

1

问题可能是您需要在 channelitem 表上为列创建日期创建索引。索引帮助数据库更快地运行查询。这是一个关于 MySQL 索引的链接

于 2013-07-10T23:01:25.190 回答
1

尝试left outer join这样的查询版本永远不会有什么坏处:

SELECT ci.ciid, ci.cid, ci.name, ci.description, ci.url, ci.creationdate, ci.author
FROM  `channelitem` ci left outer join
       (SELECT ciid
        FROM  `uninet_channelitem_read` 
        WHERE uid =  '1030'
       ) cr
       on ci.ciid = cr.ciid
where cr.ciid is null and
      ci.cid in (117, 308, 310)
ORDER BY ci.`creationdate` DESC 
LIMIT 0 , 100

uninet_channelitem_read(ciid)如果索引 on并且可能 on ,此查询会更快channelitem(cid, ciid, createddate)

于 2013-07-11T00:20:10.360 回答