I have a table called example_table with 7 million rows, and the range_optimizer_max_mem_size is set to 2MB. I understand that if a query’s range memory exceeds this limit, the optimizer switches to a full table scan. However, I noticed something interesting: when I run an UPDATE query with 4,000 IDs, it exceeds the limit and defaults to a full table scan. But when I convert that UPDATE into a SELECT query using the same 4,000 IDs, it does not exceed the range_optimizer_max_mem_size.
Can someone help me understand the difference in behavior between the SELECT and UPDATE queries?
Attached the table and test details below,
MySQL Version : 5.7.18
mysql> show create table example_table;
+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| example_table | CREATE TABLE `example_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `name` (`name`),
KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=7000001 DEFAULT CHARSET=latin1 |
+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> show indexes from example_table;
+---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| example_table | 0 | PRIMARY | 1 | id | A | 4 | NULL | NULL | | BTREE | | |
| example_table | 1 | name | 1 | name | A | 4 | NULL | NULL | YES | BTREE | | |
| example_table | 1 | email | 1 | email | A | 4 | NULL | NULL | YES | BTREE | | |
+---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
mysql> select count(*) from example_table;
+----------+
| count(*) |
+----------+
| 7000000 |
+----------+
1 row in set (1.22 sec)
mysql> explain UPDATE example_table SET age=100 where (id IN (<4k ids>) and ((id >= 1) and (id <= 7000000)));
+----+-------------+---------------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
| 1 | UPDATE | example_table | NULL | index | NULL | PRIMARY | 8 | NULL | 7000000 | 100.00 | Using where |
+----+-------------+---------------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.10 sec)
mysql> explain Select * from example_table where (id IN (<4k ids>) and ((id >= 1) and (id <= 7000000)));
+----+-------------+---------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| 1 | SIMPLE | example_table | NULL | range | PRIMARY | PRIMARY | 8 | NULL | 4000 | 100.00 | Using where |
+----+-------------+---------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+