Description:
The Optimizer seems to pick the first of multiple usable INDEXes even when not necessarily optimal.
Given these indexes:
INDEX a_ts (a, ts), -- in the way
INDEX a_b (a, b) -- clearly better
and this WHERE:
WHERE a = 2 and b = 22
`a_ts` is picked instead of `a_b`, apparently only because it is first -- for both SELECT and DELETE.
Results of EXPLAIN:
mysql> EXPLAIN DELETE FROM inx_order WHERE a = 2 and b = 22;
+----+-------------+-----------+-------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+------+---------+-------+------+-------------+
| 1 | SIMPLE | inx_order | range | a_ts,a_b | a_ts | 8 | const | 2 | Using where |
+----+-------------+-----------+-------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM inx_order WHERE a = 2 and b = 22;
+----+-------------+-----------+------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+-------+------+-------------+
| 1 | SIMPLE | inx_order | ref | a_ts,a_b | a_ts | 8 | const | 2 | Using where |
+----+-------------+-----------+------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)
Results when INDEX declarations are swapped:
mysql> EXPLAIN DELETE FROM inx_order WHERE a = 2 and b = 22;
+----+-------------+-----------+-------+---------------+------+---------+-------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+------+---------+-------------+------+-------------+
| 1 | SIMPLE | inx_order | range | a_b,a_ts | a_b | 12 | const,const | 2 | Using where |
+----+-------------+-----------+-------+---------------+------+---------+-------------+------+-------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM inx_order WHERE a = 2 and b = 22;
+----+-------------+-----------+------+---------------+------+---------+-------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+-------------+------+-------+
| 1 | SIMPLE | inx_order | ref | a_b,a_ts | a_b | 12 | const,const | 2 | NULL |
+----+-------------+-----------+------+---------------+------+---------+-------------+------+-------+
1 row in set (0.00 sec)
How to repeat:
DROP TABLE IF EXISTS inx_order;
CREATE TABLE inx_order (
id INT AUTO_INCREMENT,
a BIGINT NOT NULL,
b INT NOT NULL,
ts TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY(id),
INDEX a_ts (a, ts), -- in the way
INDEX a_b (a, b) -- clearly better
);
INSERT INTO inx_order (a,b) VALUES
(1,11), (1,11), (4,11),
(2,22), (2,22), (5,22);
EXPLAIN DELETE FROM inx_order WHERE a = 2 and b = 22;
EXPLAIN SELECT * FROM inx_order WHERE a = 2 and b = 22;
DROP TABLE IF EXISTS inx_order;
CREATE TABLE inx_order (
id INT AUTO_INCREMENT,
a BIGINT NOT NULL,
b INT NOT NULL,
ts TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY(id),
INDEX a_b (a, b), -- clearly better
INDEX a_ts (a, ts) -- out of the way
);
INSERT INTO inx_order (a,b) VALUES
(1,11), (1,11), (4,11),
(2,22), (2,22), (5,22);
EXPLAIN DELETE FROM inx_order WHERE a = 2 and b = 22;
EXPLAIN SELECT * FROM inx_order WHERE a = 2 and b = 22;
Suggested fix:
more Optimizer work.