75 mysql 两张忽略大小写同名的表改一张表名之后丢失了一张表, 改回表名丢失的表又回来了
前言
这是最近碰到的一个问题
很神奇的一个问题, 这里我们来看一下 这里的具体的情况
数据表中有两张表 DXX_TABLE, dxx_table
更新 dxx_table 为 dxx_table_bak, 之后情况为 只能够看到 dxx_table_bak 一张表
再更新 dxx_table_bak 为 dxx_table, 之后情况为, 又能够看到了 DXX_TABLE, dxx_table 两张表, 整个过程可以反复复现
这个 一度让人感觉 十分神奇, 找了一下 相关的触发器, 发现没有
information_schema.TABLES 中的数据和客户端看到的数据表列表一致
这里主要是 涉及到 lower_case_table_names 的配置对于 mysql 的影响, 以及 mysql 这边 information_schema.TABLES 的数据的填充的相关流程
问题的复现方式如下
1.初始化 mysql 的配置 lower_case_table_names 为 0, 大小写敏感
2.新建数据表 DXX_TABLE, dxx_table 两张数据表
3.更新 mysql 的配置 lower_case_table_names 为 1, 大小写部敏感
4.这时候 看到的状态就是 上面出现问题的初始化情况了
问题的情况
数据表的初始化状态
更新 dxx_table 为 dxx_table_bak 之后
将 dxx_table_bak 还原为 dxx_table 之后
从客户的理解上来说 就很神奇
明明 我只是更新了一个表的表名, 为什么 会影响到另外一个数据表 是否展示?
DXX_TABLE 和 dxx_table 均存在的情况下 information_schema.TABLES 的填充
填充 DXX_TABLE 的时候, 可以看到查询的 table 是 dxx_table, 走的 schema_table->process_table 来填充当前 DXX_TABLE 的数据记录
填充 dxx_table 的时候, 可以看到查询的 table 是 dxx_table, 走的 schema_table->process_table 来填充当前 dxx_table 的数据记录
所以 最终得到的 列表是 仅仅有 dxx_table, DXX_TABLE 两项记录
dxx_table 更新为 dxx_table_bak 之后 information_schema.TABLES 的填充
dxx_table 更新为 dxx_table_bak 之后
填充 DXX_TABLE 的时候, 可以看到查询的 table 是 dxx_table, 然后这里是 在某个流程中得到的是 NO_SUCH_TABLE 的错误, 然后跳过了 DXX_TABLE 的 记录的填充
填充 dxx_table_bak 的时候, 可以看到查询的 table 是 dxx_table_bak, 走的 schema_table->process_table 来填充当前 dxx_table_bak 的数据记录
所以 最终得到的 列表是 仅仅只有 dxx_table_bak 一项记录
dxx_table 更新为 dxx_table_bak 之后fill_schema_table_by_open 中为什么在找 DXX_TABLE 相关表的时候 查询的是 dxx_table ?
在 fill_schema_table_by_open 中根据表名获取 TABLE_LIST 的时候, 其中有关于 lower_case_table_names 的处理, 将表名转换为小写的表名
处理之前为大写的 DXX_TABLE
配置了 lower_case_table_names, 将 DXX_TABLE 更新为 dxx_table
dxx_table 更新为 dxx_table_bak 之后fill_schema_table_by_open 中查找 dxx_table 为什么结果是 ER_NO_SUCH_TABLE
在 fill_schema_table_by_open 中打开目标数据表 dxx_table
在 open_table_def 中拿到错误, 这里处理为 NO_SUCH_TABLE
所以 我们这里关注一下 open_table_def 的处理
然后 open_table_def 这边的处理是查找的 dxx_table.frm 文件, 但是 因为我们 dxx_table 已经修改为了 dxx_table_bak, 所以 数据库的数据文件中已经没有了 dxx_table.frm, dxx_table.ibd 文件, 所以这里 打开 dxx_table.frm 报错, 进而就是 得到下游的 NO_SUCH_TABLE 的错误, 相应给 fill_schema_table_by_open 的流程
get_all_tables 遍历的数据表列表来自哪里?
在 get_all_tables 的流程中可以看到 一级遍历的是 db 列表, 比如 information_schema, performance_schema, mysql, test_02 等等
然后 下面 make_table_name_list 是查找目标 db 下面的所有的数据表
然后 make_table_name_list 中是遍历目标文件夹
然后 过滤出目标文件, 比如这里 test_02数据库下面, 那就是 dxx_table, DXX_TABLE 或者 dxx_table_bak, DXX_TABLE
总结一下 就是遍历目标数据库下面的文件, 获取数据表的名称列表
问题的解决
这个问题 如果是需要保留 lower_case_table_names 并且去掉 大小写的数据表的话
- lower_case_table_names 更新为 0 删掉目标表, lower_case_table_names 更新为 1
- 直接 数据库文件里面删除掉 目标表的 frm 和 ibd
问题的总结
- 在最初始化的状态, 可以看到 dxx_table 和 DXX_TABLE, 实际上的操作都是操作的数据表 dxx_table, 所以 查询, 重命名, 所以这里例子中不管是更新 dxx_table, DXX_TABLE 的名字 都可以复现问题, 并且都是更新的数据表 dxx_table
- 在最初始化的状态下面, 看到的 dxx_table, DXX_TABLE, 整个过程是遍历 test02 文件夹拿到 dxx_table, DXX_TABLE, 然后后面 fill_schema_table_by_open dxx_table 本身就能够填充记录, 对于 DXX_TABLE, 获取的是 dxx_table 的数据表相关信息, 然后 能够拿到 dxx_table, DXX_TABLE 的数据记录
- 在 dxx_table 更新为 dxx_table_bak 之后, 整个过程是遍历 test02 文件夹拿到 dxx_table_bak, DXX_TABLE, 然后后面 fill_schema_table_by_open dxx_table_bak 本身就能够填充记录, 对于 DXX_TABLE, 获取的是 dxx_table 的数据表相关信息, 获取不到 被过滤掉了, 然后 只能够拿到 dxx_table_bak 的数据记录
- 在 dxx_table_bak 更新回 dxx_table 之后, 整个过程是遍历 test02 文件夹拿到 dxx_table, DXX_TABLE, 然后后面 fill_schema_table_by_open dxx_table_ 本身就能够填充记录, 对于 DXX_TABLE, 获取的是 dxx_table 的数据表相关信息, 然后 能够拿到 dxx_table, DXX_TABLE 的数据记录
另外比如 数据表创建的均是大写, 然后之后将 lower_case_table_names 由大小写敏感更新为了大小写不敏感, 可能会出现 所有的数据表都丢了的情况
完
原文地址:https://blog.csdn.net/u011039332/article/details/136001468
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!