提问者:小点点

按PM父id分组时MySQL查询缓慢(vBulletin数据库)


我想像IM那样从vBulletin中获取所有的PMs,这应该在我的。NET Core库中使用Dapper。 这意味着:A向B发送消息,B回复将是一个带有两条消息的对话。 由于这会导致性能问题,所以我尝试使用DBeaver通过直接运行Dapper查询来解决这个问题。

要从收件箱中获取页面的对话,我编写了以下查询:

SELECT pm.pmid
FROM pm, pmtext AS txt
WHERE pm.pmtextid = txt.pmtextid 
AND (pm.userid = 123 OR txt.fromuserid = 123)
AND pm.folderid != -1
GROUP BY IF(pm.parentpmid != 0, pm.parentpmid, pm.pmid)
LIMIT 0, 50

这给了我用户#123的前50个会话ID。 它可以工作,但执行时间约为440ms。 我尝试向所有相关字段添加索引

ALTER TABLE pmtext ADD INDEX fromuserid_only(fromuserid);
ALTER TABLE pm ADD INDEX userid_only(userid);
ALTER TABLE pm ADD INDEX parentpmid(parentpmid);

但还是很慢。 这似乎是由组by引起的。 即使我只执行按pm.parentpmid分组(这会产生错误的数据,但只是为了性能测试),查询运行时间也不会更好。 当我通过删除组时,它非常快(12ms)。

我计算对话总页数的查询在没有联接及其快速(<20ms):

// DbConnection db = ...
string sqlTotalPages = @"
    SELECT CEIL(COUNT(*)/ 50) AS pages
   FROM pm, pmtext AS txt
    WHERE pm.pmtextid = txt.pmtextid 
    AND (pm.userid = 18 OR txt.fromuserid = 18)";
int totalPages = db.QueryFirstOrDefault<int>(sqlTotalPages);

为什么group by会大大降低查询速度? 我怎样才能提高绩效?

CREATE TABLE `pm` (
  `pmid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `pmtextid` int(10) unsigned NOT NULL DEFAULT '0',
  `userid` int(10) unsigned NOT NULL DEFAULT '0',
  `folderid` smallint(6) NOT NULL DEFAULT '0',
  `messageread` smallint(5) unsigned NOT NULL DEFAULT '0',
  `parentpmid` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`pmid`),
  KEY `pmtextid` (`pmtextid`),
  KEY `userid` (`userid`,`folderid`),
  KEY `userid_only` (`userid`),
  KEY `parentpmid` (`parentpmid`)
) ENGINE=MyISAM AUTO_INCREMENT=221965 DEFAULT CHARSET=latin1

CREATE TABLE `pmtext` (
  `pmtextid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `fromuserid` int(10) unsigned NOT NULL DEFAULT '0',
  `fromusername` varchar(100) NOT NULL DEFAULT '',
  `title` varchar(250) NOT NULL DEFAULT '',
  `message` mediumtext,
  `touserarray` mediumtext,
  `iconid` smallint(5) unsigned NOT NULL DEFAULT '0',
  `dateline` int(10) unsigned NOT NULL DEFAULT '0',
  `showsignature` smallint(5) unsigned NOT NULL DEFAULT '0',
  `allowsmilie` smallint(5) unsigned NOT NULL DEFAULT '1',
  `reportthreadid` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`pmtextid`),
  KEY `fromuserid` (`fromuserid`,`dateline`),
  KEY `fromuserid_only` (`fromuserid`),
  KEY `fromuserid_only2` (`fromuserid`)
) ENGINE=MyISAM AUTO_INCREMENT=118470 DEFAULT CHARSET=latin1

共1个答案

匿名用户

我认为GROUP BY之所以会导致诸如处理时间的增加是因为限制。 当没有GROUP BY时,DB引擎可以在找到50个符合条件的行后停止处理查询中的行。 使用GROUP BY子句,整个表需要处理,分组在一起,然后返回50个第一个结果。 至于solution,如果删除组BY并在where子句中添加“and pm.parentpmid=0”,会得到正确的结果吗? GROUP BY子句似乎是用来从结果中移除具有父项的行的,使用WHERE可以更有效地完成此操作(假设所有具有父项的行在结果中也具有父项)。