惊!使用外键竟导致mysql无法访问!

Posted _雪辉_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了惊!使用外键竟导致mysql无法访问!相关的知识,希望对你有一定的参考价值。

一、问题复现

表结构

create table t1(id varchar(50) not null primary key, c1 int) DEFAULT CHARSET=utf8mb4;
create table t2(id int, c1 varchar(50),
KEY `idx1` (`c1`),
CONSTRAINT fk_idx1 FOREIGN KEY (`c1`) REFERENCES `t1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

当foreign_key_checks为ON时,外键字段无法变更COLLATE

root@localhost 16:48:  [sbtest]> show variables like '%foreign_key_checks%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| foreign_key_checks | ON    |
+--------------------+-------+
1 row in set (0.01 sec)
root@localhost 16:52:  [sbtest]> alter table t1 modify `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;
ERROR 1833 (HY000): Cannot change column 'id': used in a foreign key constraint 'fk_idx1' of table 'sbtest.t2'
root@localhost 16:53:  [sbtest]> set foreign_key_checks=off;
Query OK, 0 rows affected (0.00 sec)

root@localhost 17:08:  [sbtest]>
root@localhost 17:08:  [sbtest]> alter table t1 modify `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

重启实例后t2表无法访问

root@localhost 17:16:  [sbtest]> select * from t1;
+----+------+
| id | c1   |
+----+------+
| a  |    1 |
+----+------+
1 row in set (0.01 sec)

root@localhost 17:16:  [sbtest]> select * from t2;
ERROR 1146 (42S02): Table 'sbtest.t2' doesn't exist
root@localhost 17:16:  [sbtest]> show create table t2;
ERROR 1146 (42S02): Table 'sbtest.t2' doesn't exist
root@localhost 17:16:  [sbtest]> show tables;
+------------------+
| Tables_in_sbtest |
+------------------+
| sbtest1          |
| t1               |
| t2               |
+------------------+
3 rows in set (0.00 sec)
root@localhost 17:18:  [sbtest]> select * from information_schema.tables where table_schema='sbtest';
+---------------+--------------+------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------------+
| TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | TABLE_TYPE | ENGINE | VERSION | ROW_FORMAT | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH | MAX_DATA_LENGTH | INDEX_LENGTH | DATA_FREE | AUTO_INCREMENT | CREATE_TIME         | UPDATE_TIME | CHECK_TIME | TABLE_COLLATION    | CHECKSUM | CREATE_OPTIONS | TABLE_COMMENT |
+---------------+--------------+------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------------+
| def           | sbtest       | sbtest1    | BASE TABLE | InnoDB |      10 | Dynamic    |      63158 |            374 |    23642112 |               0 |      2359296 |   7340032 |           NULL | 2021-06-03 11:19:49 | NULL        | NULL       | utf8mb4_general_ci |     NULL |                |               |
| def           | sbtest       | t1         | BASE TABLE | InnoDB |      10 | Dynamic    |          0 |              0 |       16384 |               0 |            0 |         0 |           NULL | 2021-06-20 17:09:43 | NULL        | NULL       | utf8mb4_general_ci |     NULL |                |               |
+---------------+--------------+------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------------+
2 rows in set (0.00 sec)

二、问题分析

查看错误日志

2021-06-20T17:16:18.633707+08:00 2 [Warning] InnoDB: Load table `sbtest`.`t2` failed, the table has missing foreign key indexes. Turn off 'foreign_key_checks' and try again.
2021-06-20T17:16:20.359356+08:00 2 [Warning] InnoDB: Load table `sbtest`.`t2` failed, the table has missing foreign key indexes. Turn off 'foreign_key_checks' and try again.
2021-06-20T17:16:20.359391+08:00 2 [Warning] InnoDB: Cannot open table sbtest/t2 from the internal data dictionary of InnoDB though the .frm file for the table exists. Please refer to http://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting.html for how to resolve the issue.

  从错误日志得出家在数据无法加载,尝试关闭foreign_key_checks解决;尽管表frm存在,但是无法从数据字典打开表。

root@localhost 17:35:  [sbtest]> set foreign_key_checks=off;
Query OK, 0 rows affected (0.00 sec)

root@localhost 17:35:  [sbtest]> select * from information_schema.tables where table_name='t2' and table_schema='sbtest';
+---------------+--------------+------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------------+
| TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | TABLE_TYPE | ENGINE | VERSION | ROW_FORMAT | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH | MAX_DATA_LENGTH | INDEX_LENGTH | DATA_FREE | AUTO_INCREMENT | CREATE_TIME         | UPDATE_TIME | CHECK_TIME | TABLE_COLLATION    | CHECKSUM | CREATE_OPTIONS | TABLE_COMMENT |
+---------------+--------------+------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------------+
| def           | sbtest       | t2         | BASE TABLE | InnoDB |      10 | Dynamic    |          0 |              0 |       16384 |               0 |        16384 |         0 |           NULL | 2021-06-20 16:48:21 | NULL        | NULL       | utf8mb4_general_ci |     NULL |                |               |
+---------------+--------------+------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------------+
1 row in set (0.00 sec)
root@localhost 17:35:  [sbtest]> show create table t2;
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                    |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `id` int(11) DEFAULT NULL,
  `c1` varchar(50) DEFAULT NULL,
  KEY `idx1` (`c1`),
  CONSTRAINT `fk_idx1` FOREIGN KEY (`c1`) REFERENCES `t1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

结论:关闭foreign_key_checks后,修改外键字段COLLATE导致重启后加载字典信息无法完成,无法完成整个innodb表的load操作。从而在查询这个表的时候报表不存在。
解决方案:

  • 关闭foreign_key_checks(不推荐)
  • 修改COLLATE为一致(推荐)

以上是关于惊!使用外键竟导致mysql无法访问!的主要内容,如果未能解决你的问题,请参考以下文章

MySQL表rename导致的外键问题

MySQL 外键,无法创建表(错误号:150)

MySQL - #1215 - 无法添加外键约束

mysql 删除表 外键出错

MySQL 外键约束 - 错误 1452 - 无法添加或更新子行

如何修复此错误 3734:无法在 MySQL WorkBench 上添加外键约束?