| Bug #111952 | Row constructor inequality comparison on Primary Key results in full table scan. | ||
|---|---|---|---|
| Submitted: | 2 Aug 2023 19:50 | Modified: | 2 Mar 20:31 |
| Reporter: | Jean-François Gagné | Email Updates: | |
| Status: | Verified | Impact on me: | |
| Category: | MySQL Server: Optimizer | Severity: | S2 (Serious) |
| Version: | 8.0, 8.0.34, 8.0.45, 5.7.43, 8.1.0, 8.4, 8.4.8 | OS: | Any |
| Assigned to: | CPU Architecture: | Any | |
[2 Aug 2023 19:50]
Jean-François Gagné
[3 Aug 2023 7:43]
MySQL Verification Team
Hello Jean-François, Thank you for the report and feedback. Verified as described. regards, Umesh
[30 Oct 2024 6:12]
tianfeng li
It seems to be the duplicate issue as BUG#108116, and a contribution that improves the row constructor expression optimization was submitted.
[2 Mar 20:31]
Jean-François Gagné
Was Version: 8.0.34, 5.7.43, 8.1.0; added 8.0, 8.0.45, 8.4, 8.4.8.
--
-- Explain for the expanded row constructor condition shows a range scan,
-- with the query being quick, and only calling the storage engine / examining rows as needed.
mysql [localhost:8045] {msandbox} (test_jfg) > explain select p, i from u where (p = 25001 and i > 50) or p > 25001 order by p, i limit 1 offset 99\G flush status; select p, i from u where (p = 25001 and i > 50) or p > 25001 order by p, i limit 1 offset 99; show status like 'Handler_read_%';
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: u
partitions: NULL
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 12
ref: NULL
rows: 955168
filtered: 100.00
Extra: Using where; Using index
1 row in set, 1 warning (0.01 sec)
Query OK, 0 rows affected (0.00 sec)
+-------+----+
| p | i |
+-------+----+
| 25002 | 50 |
+-------+----+
1 row in set (0.00 sec)
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 0 |
| Handler_read_key | 2 |
| Handler_read_last | 0 |
| Handler_read_next | 99 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
+-----------------------+-------+
7 rows in set (0.00 sec)
-- Explain for the row constructor condition shows a full table scan (type: index),
-- with the query being slower than above,
-- and calling the storage engine / examining rows much more than expected.
mysql [localhost:8045] {msandbox} (test_jfg) > explain select p, i from u where (p,i) > (25001,50) order by p, i limit 1 offset 99\G flush status; select p, i from u where (p,i) > (25001,50) order by p, i limit 1 offset 99; show status like 'Handler_read_%';
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: u
partitions: NULL
type: index
possible_keys: NULL
key: PRIMARY
key_len: 12
ref: NULL
rows: 100
filtered: 100.00
Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
+-------+----+
| p | i |
+-------+----+
| 25002 | 50 |
+-------+----+
1 row in set (0.18 sec)
+-----------------------+---------+
| Variable_name | Value |
+-----------------------+---------+
| Handler_read_first | 1 |
| Handler_read_key | 1 |
| Handler_read_last | 0 |
| Handler_read_next | 2500149 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
+-----------------------+---------+
7 rows in set (0.00 sec)
---
-- Explain for the expanded row constructor condition shows a range scan,
-- with the query being quick, and only calling the storage engine / examining rows as needed.
mysql [localhost:8408] {msandbox} (test_jfg) > explain select p, i from u where (p = 25001 and i > 50) or p > 25001 order by p, i limit 1 offset 99\G flush status; select p, i from u where (p = 25001 and i > 50) or p > 25001 order by p, i limit 1 offset 99; show status like 'Handler_read_%';
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: u
partitions: NULL
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 12
ref: NULL
rows: 955168
filtered: 100.00
Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
+-------+----+
| p | i |
+-------+----+
| 25002 | 50 |
+-------+----+
1 row in set (0.00 sec)
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 0 |
| Handler_read_key | 2 |
| Handler_read_last | 0 |
| Handler_read_next | 99 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
+-----------------------+-------+
7 rows in set (0.00 sec)
-- Explain for the row constructor condition shows a full table scan (type: index),
-- with the query being slower than above,
-- and calling the storage engine / examining rows much more than expected.
mysql [localhost:8408] {msandbox} (test_jfg) > explain select p, i from u where (p,i) > (25001,50) order by p, i limit 1 offset 99\G flush status; select p, i from u where (p,i) > (25001,50) order by p, i limit 1 offset 99; show status like 'Handler_read_%';
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: u
partitions: NULL
type: index
possible_keys: NULL
key: PRIMARY
key_len: 12
ref: NULL
rows: 100
filtered: 100.00
Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
+-------+----+
| p | i |
+-------+----+
| 25002 | 50 |
+-------+----+
1 row in set (0.19 sec)
+-----------------------+---------+
| Variable_name | Value |
+-----------------------+---------+
| Handler_read_first | 1 |
| Handler_read_key | 1 |
| Handler_read_last | 0 |
| Handler_read_next | 2500149 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
+-----------------------+---------+
7 rows in set (0.00 sec)
