【发布时间】:2022-01-30 12:27:30
【问题描述】:
我有两个表:shows(横幅展示),clicks(横幅点击)。
CREATE TABLE `shows` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`data` text NOT NULL,
`created_at` date NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
KEY `created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `clicks` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`show_id` int(11) unsigned NOT NULL,
`data` text NOT NULL,
`created_at` date NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
KEY `created_at` (`created_at`),
KEY `show_constaraint_idx` (`show_id`),
CONSTRAINT `show_constaraint` FOREIGN KEY (`show_id`) REFERENCES `shows` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
每个表有 40 000 000 条记录。
我在显示表中添加了 40 000 000 条记录:
drop procedure if exists doWhile;
DELIMITER //
CREATE PROCEDURE doWhile()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE (i <= 40000000) DO
INSERT INTO `shows` (data, created_at) values (
CONCAT(MD5(RAND()), MD5(RAND())),
FROM_UNIXTIME(unix_timestamp('2021-01-01') + floor(rand() * (unix_timestamp('2021-12-31') - unix_timestamp('2021-01-01') + 1)))
);
SET i = i + 1;
END WHILE;
END;
//
CALL doWhile();
我在 clicks 表中添加了 40 000 000 条记录:
drop procedure if exists doWhile;
DELIMITER //
CREATE PROCEDURE doWhile()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE (i <= 40000000) DO
INSERT INTO `clicks` (show_id, data, created_at) values (
(FLOOR(1 + RAND() * 40000000)),
CONCAT(MD5(RAND()), MD5(RAND())),
FROM_UNIXTIME(unix_timestamp('2021-01-01') + floor(rand() * (unix_timestamp('2021-12-31') - unix_timestamp('2021-01-01') + 1)))
);
SET i = i + 1;
END WHILE;
END;
//
CALL doWhile();
SQL 查询执行时间为 10 秒:
SELECT shows.id,
shows.data,
clicks.id,
clicks.data
FROM clicks
INNER JOIN shows ON shows.id = clicks.show_id
WHERE shows.created_at = '2021-03-03'
AND clicks.created_at >= '2021-03-03'
AND clicks.created_at <= '2021-03-06'
我尝试优化 SQL 查询,但是 SQL 查询执行时间是 10 秒:
SELECT sub_shows.id,
sub_shows.data,
sub_clicks.id,
sub_clicks.data
FROM (
SELECT clicks.id,
clicks.show_id,
clicks.data
FROM clicks
WHERE clicks.created_at >= '2021-03-03' AND clicks.created_at <= '2021-03-06'
) as sub_clicks
INNER JOIN (
SELECT shows.id,
shows.data
FROM shows
WHERE shows.created_at = '2021-03-03'
) as sub_shows ON sub_shows.id = sub_clicks.show_id
如何优化查询?
回答: 将 innodb_buffer_pool_size 更改为 12G (里克·詹姆斯)
【问题讨论】:
-
在查询前运行
EXPLAIN并将结果发布在问题上 -
如果有任何条目,请查看 mysql 错误日志。您也可以为两个表尝试组合键而不是单独的键
-
这是什么版本的mysql,因为在8.0.27这个:
created_at date NOT NULL DEFAULT current_timestamp()throws:ERROR 1067 (42000): Invalid default value for 'created_at' -
多了一层子查询;摆脱它;然后我们可以进一步讨论。
-
把
innodb_buffer_pool_size改成12G,然后再检查时序。
标签: mysql join where-clause