我有以下两个表格:
CREATE TABLE `modlogs` (
`mod` int(11) NOT NULL,
`ip` varchar(39) CHARACTER SET ascii NOT NULL,
`board` varchar(58) CHARACTER SET utf8 DEFAULT NULL,
`time` int(11) NOT NULL,
`text` text NOT NULL,
KEY `time` (`time`),
KEY `mod` (`mod`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
CREATE TABLE `mods` (
`id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(30) NOT NULL,
`password` char(64) CHARACTER SET ascii NOT NULL COMMENT 'SHA256',
`salt` char(32) CHARACTER SET ascii NOT NULL,
`type` smallint(2) NOT NULL,
`boards` text CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`,`username`)
) ENGINE=MyISAM AUTO_INCREMENT=933 DEFAULT CHARSET=utf8mb4
我想使用mod的名称加入最新的日志条目,但是我的查询非常慢(需要5.23秒):
SELECT *
FROM mods LEFT JOIN
modlogs
ON modlogs.mod = mods.id
AND modlogs.time = (SELECT MAX(time)
FROM mods
WHERE mods.id = modlogs.mod
);
SO上的所有其他答案似乎也使用了从属子查询。有没有办法可以更快地返回结果?
答案 0 :(得分:1)
这是您的查询:
SELECT *
FROM mods LEFT JOIN
modlogs
ON modlogs.mod = (SELECT MAX(time)
FROM modlogs
WHERE mods.id = modlogs.mod
);
此查询没有意义。您正在将名为mod
的内容与最大时间进行比较。听起来它对我不起作用,但那时有一些非常“聪明”的数据模型。我怀疑你真的想要:
SELECT *
FROM mods LEFT JOIN
modlogs
ON mods.id = modlods.mod and
modlogs.time = (SELECT MAX(time)
FROM mods
WHERE mods.id = modlogs.mod
);
我不会以这种方式编写查询,因为join
子句中的on
条件似乎让我感到困惑。但是,你做到了。使用索引可以获得更好的性能。我建议:
create index modlogs_mod_time on modlogs(mod, time);
我会将查询写成:
SELECT *
FROM mods LEFT JOIN
modlogs
ON mods.id = modlods.mod
WHERE NOT EXISTS (SELECT 1
FROM modlogs ml2
WHERE modlogs.mod = ml2.mod and
ml2.time > modlogs.time
);
答案 1 :(得分:1)
这是另一种解决方案,将子查询放入派生表可以避免依赖子查询的问题。它只运行子查询一次。
SELECT *
FROM mods AS m
LEFT JOIN (
SELECT ml1.*
FROM modlogs AS ml1
JOIN (
SELECT `mod`, MAX(time) AS time
FROM modlogs
GROUP BY `mod`
) AS ml2 USING (`mod`, time)
) AS ml ON m.id = ml.`mod`;
答案 2 :(得分:0)
我认为你也可以用反连接解决这个问题,虽然我对这个问题的表现持怀疑态度:
SELECT mods.*, modlogs.*
FROM mods
LEFT JOIN modlogs
ON modlogs.mod = mods.id
LEFT JOIN mods m2
ON m2.id = modlogs.mod
AND m2.time < modlogs.time
WHERE m2.id IS NULL
确保您拥有modlogs(mod)
的索引,并考虑索引mods(id, time)
以获得更好的效果。