0

I have a very simple query that is running extremely slowly despite being indexed.

My table is as follows:

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

Then the following query takes more than 10 seconds to run:

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

There are about 7 million rows in the table, and approximately 200 of rows have status running.

I would expect this query to take less than a tenth of a second. It should find the first row in the index with status running. And then scan the next 200 rows until it finds the first non-running row. It should not need to look outside the index.

When I explain the query I get a very strange result:

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 |
+----+-------------+---------+------------+------+------------------------------+------------------------------+---------+-------+---------+----------+-------------+

It is estimating a scan of more than 2 million rows! Also, the cardinality of the status index does not seem correct. There are only about 5 or 6 different statuses, not 344.

Other info

  1. There are somewhat frequent insertions and updates to this table. About 2 rows inserted per second, and 10 statuses updated per second. I don't know how much impact this has, but I would not expect it to be 30 seconds worth.

  2. If I query by both status and user_id, sometimes it is fast (sub 0.1s) and sometimes it is slow (> 1s), depending on the user_id. This does not seem to depend on the size of the result set (some users with 20 rows are quick, others with 4 are slow)

Can anybody explain what is going on here and how it can be fixed?

I am using mysql version 5.7.33

23
  • 1
    Why don’t you use an index on the status column alone? If the index is on 3 columns it will not help you if you just search for status only Commented Apr 23, 2021 at 17:21
  • 1
    show create table tablename is much more readable (and complete) than describe + show indexes Commented Apr 23, 2021 at 17:28
  • consider changing your status to an integer or enum? Commented Apr 23, 2021 at 17:33
  • Looks like index is not used as index but as compact table's copy. I.e. server fullscans the index. Test does CREATE INDEX ix_status ON mytable (status) improves. Test does SELECT id FROM mytable WHERE status BETWEEN 'running' AND 'running' is fast. Commented Apr 23, 2021 at 17:48
  • 1
    As you do not say how many indexes are on the table, and you have 7 mid row in the table, maybe you index buffer in the mysql config file is too low so the index is read from disk? Commented Apr 24, 2021 at 7:10

1 Answer 1

2

As already mentioned in the comment, you are using many indexes on a big table. So the required memory for this indexes is very high. You can increase the index buffer size in the my.cnf by changing the innodb_buffer_pool_size to a higher value. But probably it is more efficient to use less indexes and do not use combined indexes if not absolutely needed. My guess is, that if you remove all indexes and create only one on status this query will run in under 1s.

Sign up to request clarification or add additional context in comments.

1 Comment

Caution: Increasing the buffer_pool too much could lead to swapping, which would hurt performance tremendously.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.