为什么在向 return 添加列时 Mysql 查询变慢?
Why does Mysql query get slow when I add a column to return?
我有一个查询 运行 很慢(在 Mysql 8 和 MariaDB 10 中):
select SQL_NO_CACHE UNIX_TIMESTAMP(created_at)* 1000 AS x,
value AS y, day(created_at), month(created_at), year(created_at)
from `portfolios`
where `user_id` = 3 and (created_at)>( CURDATE() - INTERVAL 1 MONTH)
group by day(created_at),month(created_at), year(created_at)
order by `created_at` asc;
如果我从 select 中删除 'value' 列,它运行得很快。
table是:
portfolios | CREATE TABLE `portfolios` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`value` decimal(15,8) NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `portfolios_user_id_created_at_index` (`user_id`,`created_at`),
KEY `portfolios_user_id_updated_at_index` (`user_id`,`updated_at`),
KEY `portfolios_id_user_id_updated_at_index` (`id`,`user_id`,`updated_at`),
KEY `portfolios_user_id_index` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11767164 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
table 大约有 1200 万 行。
运行 解释(没有 'value' 列):
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+------------+-------+--------------------------------------------------------------------------------------------------+-------------------------------------+---------+------+--------+-----------------------------------------------------------+
| 1 | SIMPLE | portfolios | range | portfolios_user_id_created_at_index,portfolios_user_id_updated_at_index,portfolios_user_id_index | portfolios_user_id_created_at_index | 9 | NULL | 183996 | Using where; Using index; Using temporary; Using filesort |
运行 说明(在 'value' 列):
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+------------+-------+--------------------------------------------------------------------------------------------------+-------------------------------------+---------+------+--------+--------------------------------------------------------+
| 1 | SIMPLE | portfolios | range | portfolios_user_id_created_at_index,portfolios_user_id_updated_at_index,portfolios_user_id_index | portfolios_user_id_created_at_index | 9 | NULL | 184038 | Using index condition; Using temporary; Using filesort |
因此,当我将此列添加到查询时,它似乎停止 'using where, using index' 并开始 'using index condition'。
我真的不明白为什么简单地向 select 添加一列会导致速度变慢(15 秒与大约 .3 相比)- 是因为 [=46 的大小吗=]?
如果有任何关于如何更快地获得此 运行 的建议,我将不胜感激!
提前致谢。
您的查询涉及三列:user_id
、created_at
和 value
。
您的 table 上有一些索引,但其中 none 包含 value
列。解释似乎表明 MySQL 正在使用 (user_id, updated_at)
索引来过滤匹配的行,但为了生成完整的结果,它还会扫描 table 以从 value
中提取值匹配行的列。
如果您在 (user_id, created_at, value)
上创建索引,它可以用作覆盖索引...以匹配 where 子句并从索引中查找 value
。 MySQL 不再需要触及 2200 万行 table。
此外,您的 GROUP BY
不正确。我猜您需要对一年中每一天的值进行计数或求和,在这种情况下,您需要:
SELECT UNIX_TIMESTAMP(CAST(created_at AS DATE)) * 1000, SUM(values)
FROM t
WHERE ...
GROUP BY CAST(created_at AS DATE)
ORDER BY CAST(created_at AS DATE)
我有一个查询 运行 很慢(在 Mysql 8 和 MariaDB 10 中):
select SQL_NO_CACHE UNIX_TIMESTAMP(created_at)* 1000 AS x,
value AS y, day(created_at), month(created_at), year(created_at)
from `portfolios`
where `user_id` = 3 and (created_at)>( CURDATE() - INTERVAL 1 MONTH)
group by day(created_at),month(created_at), year(created_at)
order by `created_at` asc;
如果我从 select 中删除 'value' 列,它运行得很快。
table是:
portfolios | CREATE TABLE `portfolios` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`value` decimal(15,8) NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `portfolios_user_id_created_at_index` (`user_id`,`created_at`),
KEY `portfolios_user_id_updated_at_index` (`user_id`,`updated_at`),
KEY `portfolios_id_user_id_updated_at_index` (`id`,`user_id`,`updated_at`),
KEY `portfolios_user_id_index` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11767164 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
table 大约有 1200 万 行。
运行 解释(没有 'value' 列):
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+------------+-------+--------------------------------------------------------------------------------------------------+-------------------------------------+---------+------+--------+-----------------------------------------------------------+
| 1 | SIMPLE | portfolios | range | portfolios_user_id_created_at_index,portfolios_user_id_updated_at_index,portfolios_user_id_index | portfolios_user_id_created_at_index | 9 | NULL | 183996 | Using where; Using index; Using temporary; Using filesort |
运行 说明(在 'value' 列):
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+------------+-------+--------------------------------------------------------------------------------------------------+-------------------------------------+---------+------+--------+--------------------------------------------------------+
| 1 | SIMPLE | portfolios | range | portfolios_user_id_created_at_index,portfolios_user_id_updated_at_index,portfolios_user_id_index | portfolios_user_id_created_at_index | 9 | NULL | 184038 | Using index condition; Using temporary; Using filesort |
因此,当我将此列添加到查询时,它似乎停止 'using where, using index' 并开始 'using index condition'。
我真的不明白为什么简单地向 select 添加一列会导致速度变慢(15 秒与大约 .3 相比)- 是因为 [=46 的大小吗=]?
如果有任何关于如何更快地获得此 运行 的建议,我将不胜感激!
提前致谢。
您的查询涉及三列:user_id
、created_at
和 value
。
您的 table 上有一些索引,但其中 none 包含 value
列。解释似乎表明 MySQL 正在使用 (user_id, updated_at)
索引来过滤匹配的行,但为了生成完整的结果,它还会扫描 table 以从 value
中提取值匹配行的列。
如果您在 (user_id, created_at, value)
上创建索引,它可以用作覆盖索引...以匹配 where 子句并从索引中查找 value
。 MySQL 不再需要触及 2200 万行 table。
此外,您的 GROUP BY
不正确。我猜您需要对一年中每一天的值进行计数或求和,在这种情况下,您需要:
SELECT UNIX_TIMESTAMP(CAST(created_at AS DATE)) * 1000, SUM(values)
FROM t
WHERE ...
GROUP BY CAST(created_at AS DATE)
ORDER BY CAST(created_at AS DATE)