非常简单的MySQL索引查询运行非常缓慢



我有一个非常简单的查询,尽管有索引,但运行速度非常慢。

我的表格如下:

mysql> show create table mytable
CREATE TABLE `mytable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`start_time` datetime DEFAULT NULL,
`status` varchar(64) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ix_status_user_id_start_time` (`status`,`user_id`,`start_time`),
### other columns and indices, not relevant
) ENGINE=InnoDB AUTO_INCREMENT=115884841 DEFAULT CHARSET=utf8

然后以下查询运行需要超过10秒:

select id from mytable USE INDEX (ix_status_user_id_start_time) where status = 'running';

表中大约有700万行,其中大约200行的状态为running

我预计这个查询只需要不到十分之一秒的时间。它应该找到索引中状态为running的第一行。然后扫描接下来的200行,直到找到第一个非running行。它不需要在索引之外查看。

当我解释这个查询时,我得到了一个非常奇怪的结果:

mysql> explain select id from mytable USE INDEX (ix_status_user_id_start_time) where status = 
'running';
+----+-------------+---------+------------+------+------------------------------+------------------------------+---------+-------+---------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys                | key                          | key_len | ref   | rows    | filtered | Extra       |
+----+-------------+---------+------------+------+------------------------------+------------------------------+---------+-------+---------+----------+-------------+
|  1 | SIMPLE      | mytable | NULL       | ref  | ix_status_user_id_start_time | ix_status_user_id_start_time | 195     | const | 2118793 |   100.00 | Using index |
+----+-------------+---------+------------+------+------------------------------+------------------------------+---------+-------+---------+----------+-------------+

它估计扫描超过200万行!此外,status索引的基数似乎不正确。只有大约5或6种不同的状态,而不是344种。

其他信息

  1. 此表的插入和更新有些频繁。每秒大约插入2行,每秒更新10个状态。我不知道这会产生多大的影响,但我不认为这会有30秒的价值。

  2. 如果我同时通过statususer_id进行查询,根据user_id的不同,有时它很快(低于0.1s(,有时它会很慢(>1s(。这似乎并不取决于结果集的大小(一些20行的用户很快,另一些4行的用户则很慢(

有人能解释一下这里发生了什么以及如何修复吗?

我使用的是mysql版本5.7.33

正如注释中已经提到的,您在一个大表上使用了许多索引。因此,这些索引所需的内存非常高。您可以通过将innodb_buffer_pool_size更改为更高的值来增加my.cnf中的索引缓冲区大小。但是,如果不是绝对需要的话,使用更少的索引和不使用组合索引可能会更有效。我的猜测是,如果删除所有索引,只在状态下创建一个索引,则该查询将在1秒内运行。

最新更新