按PM父ID(vBulletin数据库)分组时,MySQL查询速度慢

问题描述 投票:1回答:1

我想像vIM一样从vBulletin中获取所有PM,应该使用Dapper在我的.NET Core库中使用它。这意味着:向B发送消息,B答复将是一次对话,其中包含两条消息。由于这会导致性能问题,因此我尝试通过直接运行Dapper查询来使用DBeaver来解决问题。

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

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。它可以工作,但是要花大约440毫秒才能执行。我尝试将索引添加到所有相关字段

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

但是它仍然很慢。似乎是由GROUP BY引起的。即使我只执行GROUP BY pm.parentpmid(会产生错误的数据,但仅用于性能测试),查询运行时间也不会更好。当我删除GROUP BY时,它的速度非常快(〜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如此大幅度地降低查询速度?如何改善效果?

vB中的表结构

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
c# mysql asp.net-core mariadb vbulletin
1个回答
0
投票

我认为GROUP BY导致诸如处理时间增加的原因是由于LIMIT。如果没有GROUP BY,数据库引擎一旦发现50个符合您的条件的查询,便可以停止处理查询中的行。使用GROUP BY子句,虽然需要处理整个表,将它们分组在一起,然后将返回50个第一结果。至于解决方案,如果删除了GROUP BY并在WHERE子句中添加了“ AND pm.parentpmid = 0”,您将得到正确的结果吗?似乎GROUP BY子句可以从结果中删除带有父级的行,而使用WHERE可以更有效地完成此操作(假设所有带有父级的行在结果中也都带有父级)。

© www.soinside.com 2019 - 2024. All rights reserved.