mysql not in 查询引发的bug问题记录

数据准备

版本信息

mysql 8.0.13

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.13    |
+-----------+
1 row in set (0.00 sec)

建表语句

create table t_null_test(
  id bigint primary key auto_increment,
  city varchar(100) comment '居住城市',
  user_id bigint comment '用户ID'
) charset=utf8mb4 comment = 'not in null测试表';

create table t_user(
id bigint primary key auto_increment,
name varchar(50) comment '姓名'
) charset=utf8mb4;

查看表信息
show create table t_null_test\G

mysql> show create table t_null_test\G;
*************************** 1. row ***************************
       Table: t_null_test
Create Table: CREATE TABLE `t_null_test` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `city` varchar(100) DEFAULT NULL COMMENT '居住城市',
  `user_id` bigint(20) DEFAULT NULL COMMENT '用户ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='not in null测试表'
1 row in set (0.00 sec)

ERROR:
No query specified

mysql> show create table t_user\G;
*************************** 1. row ***************************
       Table: t_user
Create Table: CREATE TABLE `t_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL COMMENT '姓名',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

ERROR:
No query specified

测试数据

insert into t_null_test(city, user_id) values('佛山', 'cd'),('广州', 'scd'), ('深圳', 'ss'), ('东莞', null);
mysql> insert into t_null_test(city, user_id) values('佛山', 1),('广州', 2), ('深圳', 3), ('东莞', null);
Query OK, 4 rows affected (0.16 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from t_null_test;
+----+------+---------+
| id | city | user_id |
+----+------+---------+
|  1 | 佛山 |       1 |
|  2 | 广州 |       2 |
|  3 | 深圳 |       3 |
|  4 | 东莞 |    NULL |
+----+------+---------+
4 rows in set (0.00 sec)

mysql> insert into t_user(name) values('scd'),('cd'),('ss'),('sss');
Query OK, 4 rows affected (0.18 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from t_user;
+----+------+
| id | name |
+----+------+
|  1 | scd  |
|  2 | cd   |
|  3 | ss   |
|  4 | sss  |
+----+------+
4 rows in set (0.00 sec)

问题说明

使用 not in 查询

mysql> select * from t_user where id not in (select user_id from t_null_test);
Empty set (0.07 sec)

这条有问题的sql 主要的功能是从t_user表中筛选出那些id值不在t_null_test表的user_id列中的记录,查询出的结果为空,实际上是有一个id=4不存在 t_null_test表的

问题分析以及正确写法

执行逻辑

  1. 先执行子查询select user_id from t_null_test获取所有user_id值
  2. 主查询检查t_user表中每条记录的id是否不在子查询结果集中
  3. 最终返回满足条件的完整用户记录

错误问题分析

NOT IN在处理包含NULL值的子查询时可能返回意外结果,因为NULL值的比较会返回UNKNOWN而非TRUE/FALSE

性能分析

当子查询结果集较大时性能较差,因为它需要对子查询结果进行哈希匹配

正确写法

  1. 过滤 null 数据
mysql> select * from t_user where id not in (select user_id from t_null_test where user_id is not null);
+----+------+
| id | name |
+----+------+
|  4 | sss  |
+----+------+
1 row in set (0.00 sec)
  1. 使用 not exists (推荐)
mysql> select * from t_user u where not exists (select 1 from t_null_test t where u.id=t.user_id);
+----+------+
| id | name |
+----+------+
|  4 | sss  |
+----+------+
1 row in set (0.00 sec)
  1. 使用left join 过滤 null
mysql> explain select * from t_user u left join t_null_test t on u.id=t.user_id where t.user_id is null;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | u     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | NULL                                               |
|  1 | SIMPLE      | t     | NULL       | ALL  | idx_user_id   | NULL | NULL    | NULL |    4 |    25.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

为啥推荐 not exists, 查看sql 执行计划分析

mysql> explain select * from t_user u where not exists (select 1 from t_null_test t where u.id=t.user_id);
+----+--------------------+-------+------------+------+---------------+-------------+---------+-----------+------+----------+-------------+
| id | select_type        | table | partitions | type | possible_keys | key         | key_len | ref       | rows | filtered | Extra       |
+----+--------------------+-------+------------+------+---------------+-------------+---------+-----------+------+----------+-------------+
|  1 | PRIMARY            | u     | NULL       | ALL  | NULL          | NULL        | NULL    | NULL      |    4 |   100.00 | Using where |
|  2 | DEPENDENT SUBQUERY | t     | NULL       | ref  | idx_user_id   | idx_user_id | 9       | test.u.id |    1 |   100.00 | Using index |
+----+--------------------+-------+------------+------+---------------+-------------+---------+-----------+------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec)

mysql> explain select * from t_user where id not in (select user_id from t_null_test where user_id is not null);
+----+--------------------+-------------+------------+----------------+---------------+-------------+---------+------+------+----------+--------------------------+
| id | select_type        | table       | partitions | type           | possible_keys | key         | key_len | ref  | rows | filtered | Extra                    |
+----+--------------------+-------------+------------+----------------+---------------+-------------+---------+------+------+----------+--------------------------+
|  1 | PRIMARY            | t_user      | NULL       | ALL            | NULL          | NULL        | NULL    | NULL |    4 |   100.00 | Using where              |
|  2 | DEPENDENT SUBQUERY | t_null_test | NULL       | index_subquery | idx_user_id   | idx_user_id | 9       | func |    2 |   100.00 | Using where; Using index |
+----+--------------------+-------------+------------+----------------+---------------+-------------+---------+------+------+----------+--------------------------+
2 rows in set, 1 warning (0.02 sec)

mysql> explain select * from t_user u left join t_null_test t on u.id=t.user_id where t.user_id is null;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | u     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | NULL                                               |
|  1 | SIMPLE      | t     | NULL       | ALL  | idx_user_id   | NULL | NULL    | NULL |    4 |    25.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

扫描行数计算 rows * filtered%

  1. not exists = 1 * 100% = 1
  2. not in = 2 * 100% = 2
  3. left join … not null = 4 * 25% = 1
2025-12-19T05:34:37.849417Z 0 [Warning] 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release. 2025-12-19T05:34:37.849496Z 0 [Note] --secure-file-priv is set to NULL. Operations related to importing and exporting data are disabled 2025-12-19T05:34:37.849866Z 0 [Note] C:\BtSoft\mysql\MySQL5.7\bin\mysqld.exe (mysqld 5.7.38-log) starting as process 8348 ... 2025-12-19T05:34:37.868526Z 0 [Note] InnoDB: Mutexes and rw_locks use Windows interlocked functions 2025-12-19T05:34:37.869014Z 0 [Note] InnoDB: Uses event mutexes 2025-12-19T05:34:37.869267Z 0 [Note] InnoDB: _mm_lfence() and _mm_sfence() are used for memory barrier 2025-12-19T05:34:37.869618Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.11 2025-12-19T05:34:37.870357Z 0 [Note] InnoDB: Number of pools: 1 2025-12-19T05:34:37.870807Z 0 [Note] InnoDB: Not using CPU crc32 instructions 2025-12-19T05:34:37.873342Z 0 [Note] InnoDB: Initializing buffer pool, total size = 256M, instances = 1, chunk size = 128M 2025-12-19T05:34:37.890813Z 0 [Note] InnoDB: Completed initialization of buffer pool 2025-12-19T05:34:37.928888Z 0 [Note] InnoDB: Highest supported file format is Barracuda. 2025-12-19T05:34:37.935781Z 0 [Note] InnoDB: Log scan progressed past the checkpoint lsn 47795629696 2025-12-19T05:34:37.936452Z 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 47795678803 2025-12-19T05:34:37.956276Z 0 [Note] InnoDB: Database was not shutdown normally! 2025-12-19T05:34:37.956614Z 0 [Note] InnoDB: Starting crash recovery. 2025-12-19T05:34:38.334975Z 0 [Note] InnoDB: 1 transaction(s) which must be rolled back or cleaned up in total 0 row operations to undo 2025-12-19T05:34:38.335541Z 0 [Note] InnoDB: Trx id counter is 101645056 2025-12-19T05:34:38.336142Z 0 [Note] InnoDB: Starting an apply batch of log records to the database... InnoDB: Progress in percent: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 2025-12-19T05:34:38.853689Z 0 [Note] InnoDB: Apply batch completed 2025-12-19T05:34:38.854109Z 0 [Note] InnoDB: Last MySQL binlog file position 0 55386, file name mysql-bin.000051 2025-12-19T05:34:38.961866Z 0 [Note] InnoDB: Cleaning up trx with id 101609997 2025-12-19T05:34:39.294080Z 0 [ERROR] InnoDB: In file '.\20251107_092631\auth.ibd', tablespace id and flags are 828 and 33, but in the InnoDB data dictionary they are 122 and 33. Have you moved InnoDB .ibd files around without using the commands DISCARD TABLESPACE and IMPORT TABLESPACE? Please refer to http://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting-datadict.html for how to resolve the issue. 2025-12-19T05:34:39.295376Z 0 [ERROR] InnoDB: Operating system error number 203 in a file operation. 2025-12-19T05:34:39.295740Z 0 [Note] InnoDB: Some operating system error numbers are described at http://dev.mysql.com/doc/refman/5.7/en/operating-system-error-codes.html 2025-12-19T05:34:39.296279Z 0 [ERROR] InnoDB: Could not find a valid tablespace file for `20251107_092631/auth`. Please refer to http://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting-datadict.html for how to resolve the issue. 2025-12-19T05:34:39.296984Z 0 [Warning] InnoDB: Ignoring tablespace `20251107_092631/auth` because it could not be opened. 2025-12-19T05:34:39.379037Z 0 [Note] InnoDB: Removed temporary tablespace data file: "ibtmp1" 2025-12-19T05:34:39.379567Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables 2025-12-19T05:34:39.380394Z 0 [Note] InnoDB: Setting file 'D:\MySQL\Data\ibtmp1' size to 12 MB. Physically writing the file full; Please wait ... 2025-12-19T05:34:39.435030Z 0 [Note] InnoDB: File 'D:\MySQL\Data\ibtmp1' size is now 12 MB. 2025-12-19T05:34:39.455825Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active. 2025-12-19T05:34:39.456485Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active. 2025-12-19T05:34:39.457305Z 0 [Note] InnoDB: Waiting for purge to start 2025-12-19T05:34:39.509818Z 0 [Note] InnoDB: 5.7.38 started; log sequence number 47795678803 2025-12-19T05:34:39.510836Z 0 [Note] Plugin 'FEDERATED' is disabled. 2025-12-19T05:34:39.514400Z 0 [Note] InnoDB: Loading buffer pool(s) from D:\MySQL\Data\ib_buffer_pool 2025-12-19T05:34:39.522762Z 0 [Note] Recovering after a crash using mysql-bin 2025-12-19T05:34:39.523590Z 0 [Note] Starting crash recovery... 2025-12-19T05:34:39.523929Z 0 [Note] Crash recovery finished. 2025-12-19T05:34:39.569369Z 0 [Note] Found ca.pem, server-cert.pem and server-key.pem in data directory. Trying to enable SSL support using them. 2025-12-19T05:34:39.569953Z 0 [Note] Skipping generation of SSL certificates as certificate files are present in data directory. 2025-12-19T05:34:39.570390Z 0 [Warning] A deprecated TLS version TLSv1 is enabled. Please use TLSv1.2 or higher. 2025-12-19T05:34:39.570890Z 0 [Warning] A deprecated TLS version TLSv1.1 is enabled. Please use TLSv1.2 or higher. 2025-12-19T05:34:39.572758Z 0 [Warning] CA certificate ca.pem is self signed. 2025-12-19T05:34:39.573483Z 0 [Note] Skipping generation of RSA key pair as key files are present in data directory. 2025-12-19T05:34:39.574195Z 0 [Note] Server hostname (bind-address): '*'; port: 3306 2025-12-19T05:34:39.574741Z 0 [Note] IPv6 is available. 2025-12-19T05:34:39.575017Z 0 [Note] - '::' resolves to '::'; 2025-12-19T05:34:39.575349Z 0 [Note] Server socket created on IP: '::'. 2025-12-19T05:34:39.604561Z 0 [Note] Failed to start slave threads for channel '' 2025-12-19T05:34:39.619077Z 0 [ERROR] InnoDB: Page [page id: space=572, page number=3] log sequence number 47818895373 is in the future! Current system log sequence number 47795679298. 2025-12-19T05:34:39.619873Z 0 [ERROR] InnoDB: Your database may be corrupt or you may have copied the InnoDB tablespace but not the InnoDB log files. Please refer to http://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html for information about forcing recovery. 2025-12-19T05:34:39.633764Z 0 [Note] Event Scheduler: Loaded 0 events 2025-12-19T05:34:39.634297Z 0 [Note] C:\BtSoft\mysql\MySQL5.7\bin\mysqld.exe: ready for connections. Version: '5.7.38-log' socket: '' port: 3306 MySQL Community Server (GPL) 2025-12-19 13:34:42 0x5d18 InnoDB: Assertion failure in thread 23832 in file fsp0fsp.cc line 3880 InnoDB: Failing assertion: xdes_mtr_get_bit(descr, XDES_FREE_BIT, header_page % FSP_EXTENT_SIZE, mtr) == FALSE InnoDB: We intentionally generate a memory trap. InnoDB: Submit a detailed bug report to http://bugs.mysql.com. InnoDB: If you get repeated assertion failures or crashes, even InnoDB: immediately after the mysqld startup, there may be InnoDB: corruption in the InnoDB tablespace. Please refer to InnoDB: http://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html InnoDB: about forcing recovery. 05:34:42 UTC - mysqld got exception 0x80000003 ; This could be because you hit a bug. It is also possible that this binary or one of the libraries it was linked against is corrupt, improperly built, or misconfigured. This error can also be caused by malfunctioning hardware. Attempting to collect some information that could help diagnose the problem. As this is a crash and something is definitely wrong, the information collection process might fail. key_buffer_size=134217728 read_buffer_size=131072 max_used_connections=4 max_threads=300 thread_count=4 connection_count=4 It is possible that mysqld could use up to key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = 403530 K bytes of memory Hope that's ok; if not, decrease some variables in the equation. Thread pointer: 0x23a27e14790 Attempting backtrace. You can use the following information to find out where mysqld died. If you see no messages after this, something went terribly wrong... 7ff63abcb302 mysqld.exe!my_errno() 7ffc6838ee1d MSVCR120.dll!raise() 7ffc68394a14 MSVCR120.dll!abort() 7ff63ace7434 mysqld.exe!?reserve@?$vector@EV?$allocator@E@std@@@std@@QEAAX_K@Z() 7ff63acfab30 mysqld.exe!?reserve@?$vector@EV?$allocator@E@std@@@std@@QEAAX_K@Z() 7ff63ac64cdf mysqld.exe!?reserve@?$vector@EV?$allocator@E@std@@@std@@QEAAX_K@Z() 7ff63ac673e6 mysqld.exe!?reserve@?$vector@EV?$allocator@E@std@@@std@@QEAAX_K@Z() 7ff63ac66f29 mysqld.exe!?reserve@?$vector@EV?$allocator@E@std@@@std@@QEAAX_K@Z() 7ff63ac63e9a mysqld.exe!?reserve@?$vector@EV?$allocator@E@std@@@std@@QEAAX_K@Z() 7ff63ac2a36e mysqld.exe!?reserve@?$vector@EV?$allocator@E@std@@@std@@QEAAX_K@Z() 7ff63ac2e5ac mysqld.exe!?reserve@?$vector@EV?$allocator@E@std@@@std@@QEAAX_K@Z() 7ffc7f294cb0 KERNEL32.DLL!BaseThreadInitThunk() 7ffc8077edcb ntdll.dll!RtlUserThreadStart() Trying to get some variables. Some pointers may be invalid and cause the dump to abort. Query (0): Connection ID (thread ID): 0 Status: NOT_KILLED The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains information that should help you find out what is causing the crash. 2025-12-19T05:34:42.715725Z 0 [Note] InnoDB: Buffer pool(s) load completed at 251219 13:34:42
最新发布
12-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chengdu.S

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值