MySQL 数据迁移中 lower_case_table_names 参数影响

文若1年前技术文章312

记一次 SQLServer 迁移至 MySQL 遇到的一个关于 lower_case_table_names 参数的问题。

前言

  将 SQLServer 数据库迁移至 MySQL 迁移过后,驼峰命名的表都变成了小写,例如:DooBeDooBa 变成了 doobedooba 本篇文章分析下原因和解决方法。

一、原因分析

MySQL 对大小写是否敏感,由 lower_case_table_names 参数来控制,修改此参数需要重启数据库才能生效,该参数由三个选项:

  • lower_case_table_names = 0:表名区分大小写,且按照用户指定存储。

    mysql> create table CmVotingRecord(
       ->     Id int auto_increment primary key ,
       ->     NameInfo varchar(20)
       -> );
    Query OK, 0 rows affected (0.02 sec)

    mysql> insert into CmVotingRecord value (1, '1');
    Query OK, 1 row affected (0.00 sec)

    mysql> insert into cmvotingrecord value (1, '1');
    ERROR 1146 (42S02): Table 'test.cmvotingrecord' doesn't exist

    mysql> show tables;
    +----------------+
    | Tables_in_test |
    +----------------+
    | CmVotingRecord |
    +----------------+

    可以看到我们创建 CmVotingRecord 表,MySQL 也是按照 CmVotingRecord 存储的,使用小写则无法操作该表。

  • lower_case_table_names = 1:表不区分大小写,使用小写存储。

    root@mysql 14:25:  [rep_test]>create table CmVotingRecord(
     ->     Id int auto_increment primary key ,
     ->     NameInfo varchar(20)
     -> );
    Query OK, 0 rows affected (0.02 sec)

    root@mysql 14:25:  [rep_test]>show tables;
    +--------------------+
    | Tables_in_rep_test |
    +--------------------+
    | cmvotingrecord     |
    +--------------------+
    1 row in set (0.01 sec)

    root@mysql 14:25:  [rep_test]>insert into CmVotingRecord value (1, '1');
    Query OK, 1 row affected (0.00 sec)

    root@mysql 14:25:  [rep_test]>insert into cmvotingrecord value (2, '1');
    Query OK, 1 row affected (0.00 sec)

    可以看到我们创建 CmVotingRecord 表,MySQL 则是按照 cmvotingrecord 小写存储的,使用 大写/小写 都可以操作该表。

  • lower_case_table_names = 2:表不区分大小写,按照用户指定存储。

    mysql> select @@lower_case_table_names;
    +--------------------------+
    | @@lower_case_table_names |
    +--------------------------+
    |                        2 |
    +--------------------------+
    1 row in set (0.00 sec)

    mysql> create table CmVotingRecord(
       ->     Id int auto_increment primary key ,
       ->     NameInfo varchar(20)
       -> );
    Query OK, 0 rows affected (0.01 sec)

    mysql> show tables;
    +------------------+
    | Tables_in_test02 |
    +------------------+
    | CmVotingRecord   |
    +------------------+
    1 row in set (0.00 sec)

    mysql>
    mysql> insert into CmVotingRecord value (1, '1');
    Query OK, 1 row affected (0.00 sec)

    mysql>
    mysql> insert into cmvotingrecord value (2, '1');
    Query OK, 1 row affected (0.00 sec)

    可以看到我们创建 CmVotingRecord 表,MySQL 是按照 CmVotingRecord 用户指定大小存储的,使用 大写/小写 都可以操作该表。

在不同系统上运行,会有不同的默认值👇

截屏2023-02-10 上午9.26.37.png

需要注意的是 在 Linux 系统中不支持设置为 2 当用户设置为 2 时,将被强制改为 0。 RDS for MySQL 默认设置为 1 且不支持设置为 2。

其实到这里问题也就有答案了,数据从 SQLServer 迁移到 MySQL 因为 lower_case_table_names 默认为 1 原本的驼峰命名全变成了小写,解决方法其实比较简单,例如写脚本订正表名,或者将 lower_case_table_names 参数设置为 0 重新导数,前者方案应该更容易让客户接受些。

二、驼峰转下划线

SQLServer 中常用驼峰命名,MySQL 中则常用 _下划线 来命名,和客户沟通后,将驼峰命令修改为下划线命令,拼接 ALTER 语句,订正 MySQL 中的表名。

def change_name(name):
   new_name = ""
   name += " "
   for i in range(len(name) - 1):
       if i == 0:
           new_name += name[i]
       elif name[i].isupper() and name[i - 1].islower():
           new_name += "_" + name[i]
       elif name[i].isupper() and name[i - 1].isupper() and name[i + 1].islower():
           new_name += "_" + name[i]
       else:
           new_name += name[i]
   return new_name.lower()


file_path = '/Users/cooh/Desktop/table_name.sql'

with open(file_path) as r:
   content = r.readlines()

for x in content:
   source = x.replace('\n', '')
   print('-- source:', source)
   alter_sql = 'ALTER TABLE {} RENAME {};'.format(source.lower(), change_name(source))
   print(alter_sql)

将迁移的表名放到文件中,然后生成批量修改表名的命令即可。

三、总结

数据库因为架构及运行环境不同,可能会有些差异,如果遇到类似问题,个人认为如果无法将 lower_case_table_names 修改为 2 用脚本订正一遍也是不错的方法。

将 lower_case_table_names 从不敏感修改为敏感,风险不大。但是如果将 lower_case_table_names 从敏感修改为不敏感,如果恰好有表名相同大小写不同的表,就会出现异常,数据库的命令只能操作 “小写” 的表,无法操作大写的表。

root@mysql 15:09:  [rep_test]>show tables;
+--------------------+
| Tables_in_rep_test |
+--------------------+
| CmVotingRecord     |
+--------------------+
1 row in set (0.00 sec)

root@mysql 15:09:  [rep_test]>select * from CmVotingRecord;
ERROR 1146 (42S02): Table 'rep_test.cmvotingrecord' doesn't exist
root@mysql 15:09:  [rep_test]>

所以该参数从 0 到 1 & 2 需要严格评估风险。



相关文章

MySQL运维实战之ProxySQL(9.8)SQL镜像

使用proxysql的镜像(mirror)功能,可以将SQL发送到一个额外的后端实例执行。还可以将发送到镜像的SQL进行改写,以测试修改后的SQL是否能正常执行。通过mirror_flagOut字段,...

数据湖技术之iceberg(九)Spark与Iceberg整合写操作

数据湖技术之iceberg(九)Spark与Iceberg整合写操作

1. INSERT INTO"insert into"是向Iceberg表中插入数据,有两种语法形式:"INSERT INTO tbl VALUES (1,"z...

MySQL运维实战(4.5) SQL_MODE之NO_ZERO_DATE和NO_ZERO_IN_DATE

NO_ZERO_DATE:日期中不允许'0000-00-00'NO_ZERO_IN_DATE:日期中年、月或日不允许为0,如不允许'2021-00-01', '...

借助arthas工具打火焰图

借助arthas工具打火焰图

1、下载arthas在命令行下面执行(使用和目标进程一致的用户启动,否则可能 attach 失败):curl -O https://arthas.aliyun.com/arthas-boot.jar...

使用clickhouse-backup备份和恢复数据

使用clickhouse-backup备份和恢复数据

介绍clickhouse-backup是altinity提供的一个clickhouse数据库备份和恢复的工具,开源项目地址:https://github.com/Altinity/clickhouse...

MySQL 初始化推荐关注的参数

MySQL 初始化推荐关注的参数

前言新部署的 MySQL 实例如何配置?本 SOP 将提供一些 MySQL 关键参数及设置方法。必须设置的参数1. innodb_buffer_pool_size对于 innodb 表引擎来说,用户数...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。