Mysql 为什么子查询比连接快?
慢: 快速 模式:Mysql 为什么子查询比连接快?,mysql,mysql-5.6,Mysql,Mysql 5.6,慢: 快速 模式: SELECT `m`.`id`, (SELECT `number` FROM `history` WHERE `memb_id` = `m`.`id` ORDER BY `id` DESC LIMIT 1) AS `number`, (SELECT `message` FROM `history` WHERE `memb_id` = `m`.`id` ORDER BY `id` DESC LIMIT 1) AS `message`,
SELECT `m`.`id`,
(SELECT `number` FROM `history` WHERE `memb_id` = `m`.`id` ORDER BY `id` DESC LIMIT 1) AS `number`,
(SELECT `message` FROM `history` WHERE `memb_id` = `m`.`id` ORDER BY `id` DESC LIMIT 1) AS `message`,
(SELECT `code` FROM `history` WHERE `memb_id` = `m`.`id` ORDER BY `id` DESC LIMIT 1) AS `code`
FROM `members` AS `m`
LEFT JOIN `reads` AS `r` ON `r`.`email` = `m`.`id`
LEFT JOIN `writes` AS `w` ON `w`.`email` = `m`.`id`
WHERE `m`.`status` = 1
AND (`r`.`reads` > 0 OR `w`.`writes` > 0)
GROUP BY `m`.`id`
;
-- members ~ 40k
-- history ~ 400k
-- reads ~ 40k
-- writes ~ 4k
-- Query duration: 0.328 sec.
-- members ~ 40k
-- history ~ 400k
-- reads ~ 400k
-- writes ~ 4k
-- Query duration: 0.343 sec.
如上所述,您的查询不是等价的。“慢速”查询获取成员的所有历史记录,然后使用GROUP BY缩小结果范围。这意味着在短时间内可能存在大量数据,但数字、消息和代码的值很可能没有引用最新的历史记录 针对子查询添加联接以获取每个成员的最新历史记录id,请尝试以下操作:-
CREATE TABLE `members` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(254) NOT NULL,
`email` VARCHAR(254) NOT NULL,
`password` VARCHAR(254) NOT NULL,
`status` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
INDEX `status` (`status`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
CREATE TABLE `recipients_history` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`memb_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
`number` INT(3) UNSIGNED NOT NULL DEFAULT '0',
`message` TEXT NOT NULL,
`code` TINYINT(2) UNSIGNED NOT NULL DEFAULT '0',
`datetime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `memb_id` (`memb_id`),
INDEX `number` (`number`),
INDEX `code` (`code`),
INDEX `datetime` (`datetime`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
-- writes uses the same schema
CREATE TABLE `reads` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`memb_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
`reads` INT(11) UNSIGNED NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
INDEX `memb_id` (`memb_id`),
INDEX `reads` (`reads`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
你用更多的数据检查过了吗?这也可能因获取的数据量而异。您遗漏了一些重要信息。例如:返回多少个结果?这两个查询的执行计划是什么?使用子查询不能很好地扩展,但是对于较小的结果集,它可能会更快。比较执行计划。他们会告诉你发生了什么。尝试使用。两个版本的查询正在做不同的事情;带有
JOIN
的版本不会限制结果集大小,而版本子查询会限制结果集大小(例如限制1
)。根据您在历史记录中拥有的内容,这些可能会非常不同。
CREATE TABLE `members` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(254) NOT NULL,
`email` VARCHAR(254) NOT NULL,
`password` VARCHAR(254) NOT NULL,
`status` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
INDEX `status` (`status`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
CREATE TABLE `recipients_history` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`memb_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
`number` INT(3) UNSIGNED NOT NULL DEFAULT '0',
`message` TEXT NOT NULL,
`code` TINYINT(2) UNSIGNED NOT NULL DEFAULT '0',
`datetime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `memb_id` (`memb_id`),
INDEX `number` (`number`),
INDEX `code` (`code`),
INDEX `datetime` (`datetime`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
-- writes uses the same schema
CREATE TABLE `reads` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`memb_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
`reads` INT(11) UNSIGNED NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
INDEX `memb_id` (`memb_id`),
INDEX `reads` (`reads`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
SELECT m.id,
h.number,
h.message,
h.code
FROM members AS m
LEFT OUTER JOIN
(
SELECT memb_id, MAX(id) as max_id
FROM history
GROUP BY memb_id
) sub1 ON m.id = sub1.memb_id
LEFT OUTER JOIN history h ON sub1.memb_id = h.memb_id AND sub1.max_id = h.id
LEFT JOIN reads AS r ON r.email = m.id
LEFT JOIN writes AS w ON w.email = m.id
WHERE m.status = 1
AND (r.reads > 0 OR w.writes > 0)