Description:
MySQL stores values in SET fields as numeric values.
Although, for indexed SET fields the optimizer is not able to perform a range scan.
How to repeat:
Simple test case:
CREATE TABLE tbl_set (my_set SET('a','b','c','d','e'), INDEX (my_set));
INSERT INTO tbl_set VALUES ('a,b'),('a,c'),('a,b'),('a,c'),('a,b'),('a,c'),('a,c'),('a,e');
INSERT INTO tbl_set VALUES ('a,b,c'),('a,b,c'),('a,b,c'),('a,b,e'),('a,c,e'),('b,c,e');
INSERT INTO tbl_set VALUES ('a,b,c,d');
INSERT INTO tbl_set VALUES ('d,e');
INSERT INTO tbl_set SELECT * FROM tbl_set;
INSERT INTO tbl_set SELECT * FROM tbl_set;
INSERT INTO tbl_set SELECT * FROM tbl_set;
mysql> SELECT COUNT(*) FROM tbl_set WHERE my_set>=8;
+----------+
| COUNT(*) |
+----------+
| 48 |
+----------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT COUNT(*) FROM tbl_set WHERE my_set>=8\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: tbl_set
type: index
possible_keys: my_set
key: my_set
key_len: 2
ref: NULL
rows: 128
Extra: Using where; Using index
1 row in set (0.00 sec)
The same applies for numeric context:
mysql> EXPLAIN SELECT COUNT(*) FROM tbl_set WHERE my_set+0>=8\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: tbl_set
type: index
possible_keys: NULL
key: my_set
key_len: 2
ref: NULL
rows: 128
Extra: Using where; Using index
1 row in set (0.00 sec)
The optimizer uses the index only as covering index, not to perform a range scan.
Suggested fix:
The optimizer should treat the SET value numerically, and therefore perform a range scan.
Description: MySQL stores values in SET fields as numeric values. Although, for indexed SET fields the optimizer is not able to perform a range scan. How to repeat: Simple test case: CREATE TABLE tbl_set (my_set SET('a','b','c','d','e'), INDEX (my_set)); INSERT INTO tbl_set VALUES ('a,b'),('a,c'),('a,b'),('a,c'),('a,b'),('a,c'),('a,c'),('a,e'); INSERT INTO tbl_set VALUES ('a,b,c'),('a,b,c'),('a,b,c'),('a,b,e'),('a,c,e'),('b,c,e'); INSERT INTO tbl_set VALUES ('a,b,c,d'); INSERT INTO tbl_set VALUES ('d,e'); INSERT INTO tbl_set SELECT * FROM tbl_set; INSERT INTO tbl_set SELECT * FROM tbl_set; INSERT INTO tbl_set SELECT * FROM tbl_set; mysql> SELECT COUNT(*) FROM tbl_set WHERE my_set>=8; +----------+ | COUNT(*) | +----------+ | 48 | +----------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT COUNT(*) FROM tbl_set WHERE my_set>=8\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tbl_set type: index possible_keys: my_set key: my_set key_len: 2 ref: NULL rows: 128 Extra: Using where; Using index 1 row in set (0.00 sec) The same applies for numeric context: mysql> EXPLAIN SELECT COUNT(*) FROM tbl_set WHERE my_set+0>=8\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tbl_set type: index possible_keys: NULL key: my_set key_len: 2 ref: NULL rows: 128 Extra: Using where; Using index 1 row in set (0.00 sec) The optimizer uses the index only as covering index, not to perform a range scan. Suggested fix: The optimizer should treat the SET value numerically, and therefore perform a range scan.