ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MySQL库与表操作全攻略:从字符集设计到数据同步实战

MySQL库与表操作全攻略:从字符集设计到数据同步实战 做服务端开发绕不开MySQL这在今天几乎算得上常识。但你真去问一个写了两年SQL的人库和表到底该怎么设计才算合规字符集为什么必须显式指定ALTER TABLE到底什么场景会锁住线上业务能一口气讲清楚的并不多。这篇我就把MySQL里最基础也最容易被轻视的“库与表的操作”完整盘一遍——从建库时字符集和排序规则的选择到建表的字段类型与约束设计再到改表、删表、数据导入导出最后把“把远程库的这张表同步到本地”这类高频诉求一并拆掉。适合刚装好MySQL、正为第一条建表语句发愁的入门选手也适合写过SQL但总是事后救火的初级后端。我会把每步操作背后的原理和踩坑点写出来尽量让你少走我走过的弯路。1. 库的创建与字符集这一步决定了后续几年你会不会遇到乱码1.1 先把“库”这个东西想明白仓库、橱柜与标签很多新手容易把MySQL的“库”理解成文件夹这个类比方向是对的但不够精确。我更愿意把它比作一栋楼里的房间MySQL实例是一整栋楼每个数据库是独立的一间房每个表是房间里的橱柜表里的每一列则是橱柜上贴的标签。房间与房间之间通过“USE”切换互不干扰生产数据和测试数据通常就用两个不同的库来隔离权限也能单独控制。这里有个值得记住的点数据库在MySQL官方文档里的术语叫schema模式/架构它的核心作用就是提供一个命名空间把表、视图、存储过程、函数等对象装在一起。正因为有这层隔离你才可以在同一个MySQL实例上同时跑业务库、日志库、备份库而不用担心表名撞车。库本身能做的操作很少翻来覆去就是创建、查看、切换、修改、删除这几件事。但恰恰是“创建”这一步很多人随手敲下去后面乱码、排序异常、JOIN报错全来了。所以库的创建必须当成一件正经事来做字符集和排序规则这两项别用默认值凑合。1.2 创建一个库字符集和排序规则别用默认值凑合我建库时几乎固定用这样一条语句CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;有几个细节值得展开。先说IF NOT EXISTS。字面意思是“如果不存在就创建存在就跳过”。这在跑脚本时非常实用——初始化脚本重复执行不会报错配合幂等部署很稳。如果不写第二次执行就会直接抛ERROR 1007 (HY000): Cant create database shop; database exists。再说utf8mb4。这是MySQL里真正的完整UTF-8编码每个字符最多占4个字节emoji、生僻字、特殊符号都能存。而MySQL里的utf8其实只是utf8mb3最多3个字节遇到emoji就会插入失败或者显示成一堆问号。所以“永远使用utf8mb4”是今天建库建表的默认准则没有之一。然后是排序规则collation。utf8mb4_0900_ai_ci中0900表示Unicode 9.0排序算法ai表示accent insensitive重音不敏感ci表示case insensitive大小写不敏感。它决定的是字符串怎么排序、怎么比较大小写比如abc和ABC在_ci规则下被视为相同。5.7时代的常见默认是utf8mb4_general_ci8.0之后默认改成utf8mb4_0900_ai_ci。两者在绝大部分场景下感觉差不多但一旦做查询JOIN、唯一索引去重排序规则不一致会直接报Illegal mix of collations错误。下面这个表建议收着混用出问题的时候回来对照字符集排序规则示例适用场景说明utf8mb4utf8mb4_0900_ai_ci8.0默认通用业务推荐首选utf8mb4utf8mb4_general_ci5.7默认兼容老环境升级迁移常用utf8mb4utf8mb4_bin区分大小写、做精确二进制比较存储URL、token等需区分大小写的字段latin1latin1_swedish_ci老系统遗留大概率要迁移尽早换还有一点经验如果整个MySQL实例里的库表全部统一成utf8mb4 utf8mb4_0900_ai_ci能省掉后面一大堆破事。我接手过一台遗留服务器库里一半表是utf8一半是utf8mb4每次联表查询都像拆弹教训可谓惨痛。1.3 查看库、进入库、修改库、删除库的实操命令建完库之后日常用到的基本命令大概这几条-- 查看当前实例所有库 SHOW DATABASES; -- 查看某个库的建库语句能直接看到字符集和排序规则 SHOW CREATE DATABASE shop\G -- 切换库 USE shop; -- 查看当前所在的库 SELECT DATABASE();这几个命令里SHOW CREATE DATABASE是很实用的排查手段。当你怀疑某个库的字符集不对不用猜直接执行这条建库语句原样返回一眼就能看出端倪。修改库的字符集也是一条语句的事ALTER DATABASE shop CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;但这里有个大坑ALTER DATABASE只影响这个库之后新建的表已存在的表以及表里的列字符集不会跟着改。也就是说你改了库的默认字符集老表该乱码还是乱码。要彻底迁移还得逐表执行ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4这个后面第3章展开说。删除库在生产环境请慎之又慎。语法很简单DROP DATABASE shop;执行完库里的表、数据、存储过程、视图全部消失且没有回收站。日常备份脚本里如果涉及DROP DATABASE建议先确认备份完整性再放行。我个人的习惯是线下开发库随便删线上库一律只能走“备份-确认-再删”的三步流程。另外补充一个信息源information_schema.SCHEMATA表记录了所有库的元数据包括字符集、排序规则用SQL查比用SHOW更灵活。例如SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA;排查“哪个库字符集不对”这条查询比挨个SHOW快得多。2. 建表实战字段类型、约束与引擎选型2.1 一张“压舱石”级别的建表语句库建好之后重头戏就是建表。我给出一张业务中很常见的订单表基本涵盖了日常80%的需求CREATE TABLE IF NOT EXISTS orders ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键, order_no VARCHAR(64) NOT NULL COMMENT 业务订单号, user_id BIGINT UNSIGNED NOT NULL COMMENT 下单用户ID, amount DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 订单金额, status TINYINT NOT NULL DEFAULT 0 COMMENT 状态0创建 1已支付 2已取消, remark VARCHAR(255) NULL DEFAULT NULL COMMENT 备注, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_id (user_id), KEY idx_created_at (created_at) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci COMMENT订单表;这条语句里每行都值得说两句。BIGINT UNSIGNED给自增主键留足空间10亿条数据也远不到上限VARCHAR(64)存订单号因为订单号通常需要精确匹配不适合用TEXTDECIMAL(10,2)存金额绝不用浮点类型TINYINT存状态比VARCHAR状态枚举更省空间、更快。索引方面主键、唯一键、普通二级索引一层层铺开把最常用的查询路径提前规划好。建表时把表注释和字段注释写全这个习惯关键时刻能救命。半年后你接手一张别人写的表没有注释的话每个字段都得靠猜有了注释结构一目了然。说句玩笑话注释是你和六个月后的自己之间唯一的沟通桥梁。2.2 数值、时间与字符串类型选型的判断点数据类型选错了后面再改表就是大工程。我在选型时习惯按下面几类逐一判断。数值类型整数优先考虑TINYINT、SMALLINT、INT、BIGINT按取值范围来。下面是参照表类型存储大小有符号范围无符号范围常用场景TINYINT1字节-128~1270~255状态码、性别、开关SMALLINT2字节-32768~327670~65535小范围计数INT4字节-2147483648~21474836470~4294967295用户数、常规IDBIGINT8字节-9223372036854775808~92233720368547758070~18446744073709551615订单ID、流水ID很多老教程喜欢写int(11)括号里的数字在MySQL 8.0已经被废弃它只表示显示宽度跟存储范围没有关系。别再被“int(11)代表最大11位数”这种说法带偏了。金额建议用DECIMAL。DECIMAL(10,2)表示总共10位有效数字、保留2位小数能精确表达金额。用FLOAT/DOUBLE存钱浮点数在二进制里无法精确表达某些十进制小数累计求和时会出现0.10.2不等于0.3的诡异情况。涉及钱精度就是命。时间类型首选DATETIME。TIMESTAMP占用空间更小但它受时区影响而且范围只到2038年。业务系统跨时区、要做长期存储DATETIME最省心。另外两个默认值写法建议记牢created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,ON UPDATE CURRENT_TIMESTAMP的意思是这一行数据只要发生UPDATE时间字段就自动刷新。很多业务需要“最后更新时间”这个默认值能让你少写一堆应用层代码。字符串类型CHAR和VARCHAR的区别在于CHAR定长、VARCHAR变长。长度固定的场景才用CHAR比如MD5、手机号长度固定其余一律VARCHAR。还有个容易忽略的地方VARCHAR的长度不是越大越好。在utf8mb4下一个字段做索引最大索引长度是3072字节除以4每个字符最多4字节大约等于768个字符。所以VARCHAR(255)做索引没问题VARCHAR(1000)就很可能超出限制报Specified key was too long。TEXT类型则更特殊它不能有默认值只能建前缀索引日常存储大文本才考虑。2.3 约束与索引这些规则在建表时就要写死约束的本质是让数据库帮你在写入前做检查而不是完全依赖应用层自觉。最常用的约束是主键PRIMARY KEY保证唯一且非空UNIQUE KEY保证业务唯一NOT NULL防止脏数据DEFAULT提供兜底值CHECK做范围检查。外键约束我个人的建议是少用或不用原因很现实MySQL的外键会在每次插入、更新时做级联检查影响性能一旦表结构复杂死锁概率也变高。现在的企业级系统普遍提倡在应用层保证数据一致性数据库只做存储和索引的活。主键选型上自增BIGINT是最简单稳妥的方案。自增主键的写入顺序跟B树索引的顺序一致插入记录时直接追加到最后不会引起中间页分裂。如果用UUID做主键随机字符串会让索引页频繁分裂、页碎片变多写入放大很严重。非要自己生成分布式ID也要选雪花算法这类趋势递增的ID而不是纯随机UUID。索引不用多建够用即可。判断标准高频查询的WHERE条件、排序字段、JOIN关联字段是索引的天然候选。比如订单表里我建了idx_user_id因为“查某用户的所有订单”是高频查询idx_created_at是因为后台列表通常按订单时间排序。这里有一个点跟热词“辅助索引如何避免回表”直接相关辅助索引先查到主键再拿主键回主表查整行数据这个过程叫回表。如果查询的字段恰好都包含在辅助索引里就不需要回表这叫覆盖索引。例如SELECT order_no FROM orders WHERE user_id 123;如果存在KEY idx_user_id (user_id, order_no)这样的联合索引MySQL直接从索引树拿到order_no避免回表一次查询快一个数量级。设计联合索引时优先把等值查询的字段放前面再把需要返回的列放到索引里“覆盖住”这是很实用的优化思路。最后说引擎业务表现在默认就是InnoDB支持事务、行级锁、崩溃恢复这也意味着不用再纠结MyISAM选择。除非你有特殊需求比如全文索引的老场景否则一条规则走天下InnoDB。3. 表结构变更与数据操作改表比建表更容易出错3.1 ALTER TABLE的5种高频姿势与锁表问题线上表结构不可能永远不变加字段、改类型、改名字都是日常。MySQL的语法说多不多说少不少常用的就这么几类-- 1. 新增字段 ALTER TABLE orders ADD COLUMN pay_time DATETIME NULL COMMENT 支付时间; -- 2. 修改字段类型/默认值 ALTER TABLE orders MODIFY COLUMN remark VARCHAR(500) NOT NULL DEFAULT ; -- 3. 改名同时改类型 ALTER TABLE orders CHANGE COLUMN remark note VARCHAR(500) COMMENT 备注; -- 4. 只改名MySQL 8.0新增 ALTER TABLE orders RENAME COLUMN note TO remark; -- 5. 给表改名 ALTER TABLE orders RENAME TO order_info;ADD是纯新增MODIFY只能改类型、默认值等不能改名CHANGE既能改名又能改类型但旧写法必须把目标类型重新写一遍RENAME COLUMN是8.0带来的语法糖只改名不碰类型定义。表改名则用RENAME TO一条语句搞定。这里重点说ALTER TABLE的锁问题。在MySQL 8.0里多数结构变更默认采用在线DDLALGORITHMINPLACE配合LOCKNONE可以让业务在变更期间继续读写不会一直锁表。但真正执行时大表的DDL依然可能卡很久原因是它需要等待元数据锁metadata lock。只要有一个长事务没提交ALTER TABLE就会排队卡住后续所有查询都可能被堵住。这是个隐蔽的线上事故源你只看到一条ALTER执行了十分钟其实业务前端的慢查询已经堆积如山。大表做结构变更稳妥方案是用gh-ost或pt-online-schema-change这类工具先拷贝临时表、追增量、最后原子换表能把锁表影响降到最低。如果是几百G的大表直接在凌晨业务低峰执行也要做好监控。还有个小技巧变更前先SHOW PROCESSLIST看看有没有长事务有的话等它结束再动手。3.2 表数据操作INSERT、UPDATE、DELETE的注意事项数据操作是DBA和开发每天打交道最多的部分几个经典坑值得单独列一下。插入数据时批量插入的效率远高于逐条插入。一次插入多条直接写INSERT INTO orders (order_no, user_id, amount, status) VALUES (A001, 1, 99.00, 0), (A002, 2, 150.00, 0), (A003, 3, 299.00, 0);另外把INSERT ... ON DUPLICATE KEY UPDATE和REPLACE INTO区分开。前者是“插不进去就更新”通常不会删除旧记录后者是“先删旧记录再插新记录”会导致自增ID变化还容易触发级联操作。生产环境如果可以优先用ON DUPLICATE KEY UPDATE。更新数据最大的坑是忘记写WHERE。虽然老生常谈但事故照旧发生。UPDATE的语义是“更新表中所有匹配的行”不写WHERE就是全表更新。正确姿势一定先写WHERE条件再回来看SET。写高风险的UPDATE先跑一条SELECT COUNT(*) FROM orders WHERE status0确认影响范围再执行更新。删除数据同样有讲究。DELETE FROM orders;这种语句会逐行标记删除但不释放磁盘空间表空间依然被占用自增ID也不会重置。想清空一张表的同时释放空间、重置自增用TRUNCATE TABLE orders。但注意TRUNCATE不可回滚而且在执行期间会对表加锁别等作用到生产环境后才后悔。大表分批删除是生产环境的标准操作DELETE FROM orders WHERE created_at 2023-01-01 LIMIT 10000;反复执行直到影响行数为0。一次删除几十万行单个事务过大不仅耗时还会带来沉重的undo日志和主从同步延迟。分批删水温一点一点降服务影响最小。4. 常见报错与排查实录网上搜得到的和没搜到的4.1 error 2002连接不上、socket路径与服务状态这个报错几乎每个MySQL新手都会撞上原文长这样ERROR 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock (2)看关键字就知道客户端默认通过Unix socket连本地MySQL结果socket文件找不到。常见原因有三个服务没起来、socket路径不是默认的、或者客户端与服务端版本配置不一致。排查顺序建议这样走# 1. 先确认服务是否在跑 systemctl status mysql service mysql status # 2. 强制走TCP连接绕过socket mysql -h127.0.0.1 -P3306 -uroot -pmysql -h127.0.0.1哪怕连本机也会走TCP协议和只用mysql默认走socket不一样。这条命令能快速区分是服务挂了还是socket路径不对。如果服务确实在跑但socket路径不对通过配置文件确认grep socket /etc/mysql/my.cnf /etc/my.cnf 2/dev/null再带参数连接mysql -uroot -p --socket/var/run/mysqld/mysqld.sock远程连接失败则又是另一类排查方向常见瓶颈是MySQL配置了bind-address127.0.0.1只允许本机连接、防火墙挡了3306端口、或者账号的host限定为localhost。看授权用SELECT user, host FROM mysql.user;至少要保证账号host是%或者明确指定的IP。4.2 锁表、元数据锁与杀会话的正确姿势“锁表了”是生产环境的高频故障词。典型现象是某条UPDATE或DDL一直卡住别的查询也全部堆积。第一步永远是看现场SHOW PROCESSLIST;重点关注State列。如果大量连接都处于Waiting for table metadata lock十有八九是前面的长事务没结束后面的DDL在排队等锁。这时候查一下当前正在跑的事务SELECT * FROM information_schema.innodb_trx\G能看到事务的开始时间、状态、执行过的SQL。确认是哪个连接造成了阻塞后再决定KILL谁KILL 12345;KILL之前一定确认会话用途杀错正跑着的业务事务可能造成数据不一致。还有一张系统表值得记sys.schema_table_lock_waitsMySQL 5.7以上专门记录表锁等待关系查一下就知道谁在等谁的锁。另一个容易忽略的锁LOCK TABLES手动锁表语句。不到万不得已不要手动锁表InnoDB本来就是行级锁业务正确性靠事务保证不需要你手动加表锁。4.3 建表异常保留字、键太长与编码混合建表报错看起来五花八门实际原因就那么几类。字段名撞上保留字报ERROR 1064 (42000): You have an error in your SQL syntax。比如建一张表字段名叫order、desc、group直接裸写在SQL里就会语法错误。解决方法是用反引号包起来CREATE TABLE t (order INT, desc VARCHAR(50));但我的建议是设计表时直接避开保留字不给自己留后患。键太长报错ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes在utf8mb4下一个字段每个字符最多占4字节建索引的VARCHAR长度超过768就会爆。比如VARCHAR(1000)直接建普通索引必报这个错。解决思路有几种缩短字段长度改用前缀索引例如KEY idx_remark (remark(100))或者降低字段字符集不推荐会引入乱码风险。最合理的还是提前评估字段长度长字符串只做前缀索引。编码混合报错ERROR 1267 (HY000): Illegal mix of collations for operation 两个表字段的排序规则不一致等值JOIN时MySQL不知道怎么比较。解决办法是统一库表字段的字符集和排序规则查询临时解决可以加COLLATE指定SELECT * FROM a JOIN b ON a.name b.name COLLATE utf8mb4_0900_ai_ci;表多了之后一条条改很痛苦所以我在第1章反复强调建库时就定好字符集和排序规则这才是治本。4.4 数据导入导出乱码、ER图导出与Workbench使用用mysqldump做逻辑备份时乱码是个高频售后问题。正确的导出姿势要显式指定字符集mysqldump -h127.0.0.1 -P3306 -uroot -p --default-character-setutf8mb4 --single-transaction shop orders orders.sql导入时同样带上字符集mysql -uroot -p --default-character-setutf8mb4 shop orders.sql客户端连接、导出文件、导入连接、目标库表四者字符集全部统一才能彻底避免乱码。--single-transaction参数对InnoDB来说用InnoDB一致性快照做备份不会锁业务写这个参数可以无脑加。很多人还想把表结构导出成ER关系图。MySQL Workbench里操作很简单菜单Database - Reverse Engineer选好连接和库下一步下一步等它逆向分析完自动生成ER图。这个图对梳理业务关系、写设计文档非常有用。DBeaver也内置了类似功能。命令行下想快速导出表结构文档用SHOW CREATE TABLE orders;或者查询information_schema.COLUMNS都能生成可读性不错的表结构清单。5. 把远程库的这张表同步到本地一道综合实战题5.1 场景拆解为什么“直接连远程库”不是好方案热词里有句话很扎心“把远程库的这张表同步到本地。提供详细操作步骤。”这几乎是每个后端都会遇到的需求生产环境有一张核心表本地开发、数据分析、一次临时调研都想要一份。最粗暴的做法是应用直连远程库但这不是好方案——公网上暴露3306端口本身就是风险每次查询都跨网络往返延迟高、占用生产资源更重要的是可能误操作生产数据。正确思路只有两条要么做一次性的逻辑备份导入要么做持续的增量同步。前者适合“我就要今天这一份数据”后者适合“我希望本地库和线上库长期保持同步”。这两条路分开讲。5.2 一次性同步mysqldump单表导出与导入实操这里假设生产库IP是192.168.1.100用户名sync_user要导出的表是shop.orders。执行mysqldump -h192.168.1.100 -P3306 -usync_user -p \ --single-transaction --default-character-setutf8mb4 \ shop orders orders.sql--single-transaction在InnoDB表上做一致性快照导出期间业务写入不受影响。导出文件传回本地方式随意scp、rsync、甚至直接本机执行都行。然后在本地建库、导入CREATE DATABASE IF NOT EXISTS shop_local DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;mysql -uroot -p --default-character-setutf8mb4 shop_local orders.sql导入完成后检查两件事一是表行数是否对得上SELECT COUNT(*) FROM shop_local.orders;二是抽样几条数据看编码是否正常。一次性同步的关键点就在这里远程导出、传输、本地导入三个环节字符集都要统一指定为utf8mb4任何一环漏了都可能出现乱码。如果整库同步把命令里的表名去掉导出的是整个库mysqldump -h192.168.1.100 -P3306 -usync_user -p --single-transaction --default-character-setutf8mb4 shop shop_full.sql5.3 持续同步用binlog主从复制实现“远程库表自动同步到本地”如果需求从“导一次”变成“每天自动有最新数据”逻辑备份就不够用了。生产环境的持续同步方案最主流的就是MySQL主从复制把生产库当作主库本地库当作从库主库的写操作写进binlog从库拉取binlog重放到本地。搭建核心步骤大致如下生产主库上操作-- 1. 创建专门用于复制的账号 CREATE USER repl% IDENTIFIED BY 强密码; GRANT REPLICATION SLAVE ON *.* TO repl%; -- 2. 查看当前binlog位置 SHOW MASTER STATUS;记录下File和Position两个字段比如mysql-bin.000001和157。然后在本地从库执行CHANGE MASTER TO MASTER_HOST192.168.1.100, MASTER_PORT3306, MASTER_USERrepl, MASTER_PASSWORD强密码, MASTER_LOG_FILEmysql-bin.000001, MASTER_LOG_POS157; START SLAVE; -- 查看复制状态 SHOW SLAVE STATUS\G看到Slave_IO_Running: Yes和Slave_SQL_Running: Yes就说明复制链路通了。MySQL 8.0里语法换成了CHANGE REPLICATION SOURCE TO和START REPLICA但本质逻辑不变。这里的关键是主库必须开启binlog且server-id不能和从库相同否则从库会拒绝连接。复制粒度上可以配置只复制某张表或某个库REPLICATE_DO_TABLE(shop.orders)写在CHANGE MASTER TO里。这种方式适合对数据实时性要求高的场景但要注意主从延迟。大事务、大表DDL都会造成从库落后延迟监控是持续同步方案的必修课。5.4 方法对比哪种同步方式适合当前阶段方案适合场景优点注意点mysqldump一次性导出临时分析、联调需要一份快照简单直接、风险低不自动更新手动重复执行主从复制持续同步本地需要实时数据、报表系统自动增量接近实时要开binlog、注意主从延迟和账号权限数据同步工具如DataX、Canal异构同步、大数据量迁移灵活可控、可断点续传部署成本高适合进阶场景在我自己的环境里日常开发联调用第一种就够了每天凌晨跑一次定时任务把需要的表导一次干净省事。真正需要给测试环境提供接近线上的数据时才上主从复制。工具没有绝对好坏匹配场景才最重要。最后再分享一点我的习惯MySQL的库表操作翻来覆去就是建、查、改、删四件事但每件事背后都有坑。我在实际维护里吃过几次亏之后慢慢养成了几个固定习惯建库必写utf8mb4绝不依赖默认值建表一定把字段注释和表注释写全哪怕慢一分钟后面省一小时改表前先看SHOW PROCESSLIST确认没有长事务任何高风险的UPDATE和DELETE都先SELECT确认影响行数再动手涉及远程库表同步在所有环节都统一字符集决不偷懒。这些习惯听起来简单但正是它们让线上事故一次次绕着我走。希望你也能在建好第一张表之后就建立起同样的谨慎。
返回列表