高效查询 MySQL 中索引 int 列的前两位数

Efficiently query on first two digits of indexed int column in MySQL

我有一个 table(MySQL 8.0.26,InnoDB)包含 MEDIUMINT 的索引列,表示记录的创建日期:

date_created MEDIUMINT NOT NULL
INDEX idx_created (date_created)

例如,条目“210516”表示 2021-05-16。

以下查询在利用索引方面的效率大致相同吗?

WHERE 210000<=date_created AND date_created<220000,

WHERE date_created DIV 10000 = 21,

WHERE date_created LIKE '21%',以及

WHERE LEFT(date_created, 2) = '21'

我目前在我的代码中使用 WHERE date_created DIV 10000 = 21,但想知道我是否应该更改所有查询以提高它们的效率。

非常感谢。

查看 EXPLAIN 中的 type 列。如果它显示“ALL”,则意味着它必须对所有行执行 table-scan,为每一行评估条件表达式。这不是使用索引。

mysql> explain select * from mytable where 21000<=date_created and date_created < 22000;
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | mytable | NULL       | range | date_created  | date_created | 4       | NULL |    1 |   100.00 | Using index condition |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+

mysql> explain select * from mytable where date_created like '21%';
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | mytable | NULL       | ALL  | date_created  | NULL | NULL    | NULL | 8192 |    11.11 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+

mysql> explain select * from mytable where date_created div 10000 = 21;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | mytable | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 8192 |   100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+

mysql> explain select * from mytable where left(date_created, 2) = '21';
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | mytable | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 8192 |   100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+

MySQL 8.0 支持表达式索引,这有助于一些情况:

mysql> alter table mytable add index expr1 ((left(date_created, 2)));

mysql> explain select * from mytable where left(date_created, 2) = '21';
+----+-------------+---------+------------+------+---------------+-------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key   | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+-------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | mytable | NULL       | ref  | expr1         | expr1 | 11      | const | 1402 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+-------+---------+-------+------+----------+-------+

mysql> alter table mytable add index expr2 ((date_created DIV 10000));

mysql> explain select * from mytable where date_created div 10000 = 21;
+----+-------------+---------+------------+------+---------------+-------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key   | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+-------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | mytable | NULL       | ref  | expr2         | expr2 | 5       | const | 1402 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+-------+---------+-------+------+----------+-------+

但是表达式索引对 LIKE '21%' 搜索没有帮助,因为您必须 hard-code 索引定义表达式中的值 '21%'。您可以使用该索引仅搜索该值,而不是其他年份的值。