mysql - Mysql 在查询 tinyint 布尔字段时的奇怪行为
问题描述
我有一个voucher_codes
具有以下架构的 mysql 表:
mysql> describe voucher_codes;
+--------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(10) unsigned | YES | MUL | NULL | |
| promo_code | varchar(30) | YES | MUL | NULL | |
| voucher_value | double | NO | | NULL | |
| date_created | datetime(6) | NO | | NULL | |
| date_modified | datetime(6) | NO | | NULL | |
| redeem_flag | tinyint(1) | NO | | NULL | |
| fk_voucher_rule_id | int(11) | NO | MUL | NULL | |
+--------------------+------------------+------+-----+---------+----------------+
表上定义的索引如下:
mysql> show index from voucher_codes;
+---------------+------------+--------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------+------------+--------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| voucher_codes | 0 | PRIMARY | 1 | id | A | 15280692 | NULL | NULL | | BTREE | | |
| voucher_codes | 1 | voucher_codes_user_id | 1 | user_id | A | 2805369 | NULL | NULL | YES | BTREE | | |
| voucher_codes | 1 | voucher_codes_promo_code | 1 | promo_code | A | 7389780 | NULL | NULL | YES | BTREE | | |
| voucher_codes | 1 | fk_voucher_rule_id | 1 | fk_voucher_rule_id | A | 60 | NULL | NULL | | BTREE | | |
+---------------+------------+--------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
其中,voucher_code 为 1,redeem_flag 为 0 和 1 的记录数如下:
mysql> select count(*) from voucher_codes where redeem_flag =0 and fk_voucher_rule_id=1;
+----------+
| count(*) |
+----------+
| 135114 |
+----------+
1 row in set (3.17 sec)
mysql> select count(*) from voucher_codes where redeem_flag =1 and fk_voucher_rule_id=1;
+----------+
| count(*) |
+----------+
| 1575024 |
+----------+
1 row in set (2.56 sec)
有 1.5+ 百万条记录redeem_flag
as1
和 100k+ are 0
。
但是与使用 0 的查询相比,使用redeem_flag
as的查询花费的时间更少。结果如下:1
redeem_flag
mysql> select promo_code from voucher_codes where redeem_flag =0 and fk_voucher_rule_id=1 limit 1 ;
+--------------+
| promo_code |
+--------------+
| XXXXXXXXXX |
+--------------+
1 row in set (3.67 sec)
mysql> explain select promo_code from voucher_codes where redeem_flag =0 and fk_voucher_rule_id=1 limit 1 ;
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
| 1 | SIMPLE | voucher_codes | NULL | ref | fk_voucher_rule_id | fk_voucher_rule_id | 4 | const | 3258352 | 10.00 | Using where |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
用redeem_flag
as 1 查询:
mysql> select promo_code from voucher_codes where redeem_flag =1 and fk_voucher_rule_id=1 limit 1 ;
+------------+
| promo_code |
+------------+
| XXXXXXXXX |
+------------+
1 row in set (0.00 sec)
mysql> explain select promo_code from voucher_codes where redeem_flag =1 and fk_voucher_rule_id=1 limit 1 ;
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
| 1 | SIMPLE | voucher_codes | NULL | ref | fk_voucher_rule_id | fk_voucher_rule_id | 4 | const | 3258352 | 10.00 | Using where |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
无法理解这种行为。即使索引fk_voucher_rule_id
正在被使用,但与更少的记录相比,更多的记录需要更多的时间。
更新:添加显示创建表结果:
mysql> show create table voucher_codes;
+---------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| voucher_codes | CREATE TABLE `voucher_codes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned DEFAULT NULL,
`promo_code` varchar(30) DEFAULT NULL,
`voucher_value` double NOT NULL,
`date_created` datetime(6) NOT NULL,
`date_modified` datetime(6) NOT NULL,
`redeem_flag` tinyint(1) NOT NULL,
`fk_voucher_rule_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `voucher_codes_user_id` (`user_id`),
KEY `voucher_codes_promo_code` (`promo_code`),
KEY `fk_voucher_rule_id` (`fk_voucher_rule_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16305657 DEFAULT CHARSET=latin1 |
+---------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
解决方案
首先,使用SELECT SQL_NO_CACHE ...
而不是仅仅测试查询的速度SELECT ...
。查询在 0.00 时间内运行是很奇怪的。
此外,创建一个复合索引redeem_flag, fk_voucher_rule
,然后重新测试您的查询以进行比较。
注意:您应该在查询中使用与索引中相同的字段顺序。此外,正如@Raymod Nijland 所说,删除冗余索引。例如,如果您有索引fk_voucher_rule, redeem_flag
,它将同时用于仅使用的查询fk_voucher_rule
和fk_voucher_rule, redeem_flag
查询(其他方式不适用,您不能仅将其用于查询redeem_flag
)。
推荐阅读
- amazon-web-services - API Gateway 更改 url 调用和 api 密钥
- python-3.x - 如何使用 Python/matplotlib 获取图表的图例
- amazon-sagemaker - 如何在 SageMaker 管道中创建超参数调整步骤?
- c - 会打印什么?
- php - 用包含混合内容的字符串中的缩小 url 替换所有 url
- python - 如何将 .model 转换为 .tflite?
- git - 我如何 git 分支
在全球范围内 - swift - iOS 14 上的 PKToolPicker 颜色选择器暗模式
- flutter - 将标记捕捉到最近的折线点谷歌地图颤动
- python - 多处理池似乎甚至没有调用函数?