阿里云rds for mysql 大表添加字段复制到自建备库报错,解决过程

本文记录了一次针对含有约3600万条数据的大表进行在线DDL操作的经历,详细描述了在MySQL 5.6版本下执行该操作遇到的问题及解决过程,包括临时空间占用、复制延迟等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

表的大小大概3600W数据,一次添加多个字段(12个字段)
使用的是mysql5.6 在线ddl操作
在rds上大概执行了70多分钟,添加完毕
临时空间大概使用70个G

监控自建备库的执行,执行大概1个小时报错如下:
2018-08-06 21:16:13 7fcb4613d700 InnoDB: Error: Write to file (merge) failed at offset 31842107392.
InnoDB: 1048576 bytes should have been written, only 90112 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.6/en/operating-system-error-codes.html
2018-08-06 21:16:13 19593 [ERROR] Slave SQL: Error 'Temporary file write failure.' on query. Default database: 'ee_ertt'. Query: 'ALTER TABLE da44sdfdftle ADD `shiftInNum` DOUBLE (16, 5) DEFAULT 0 COMMENT '璋妯?
',^M伴
 ADD `shiftInCost` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '璋妯?
 ADD `shiftOutNum` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '璋妯搴搴姘?,^M
 ADD `shiftOutCost` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '璋妯搴搴殚?^M
殒惰揣姘?,^MceiptNum` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '?
殒惰揣殚?^MeceiptCost` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '?
娑璐ф伴',^MReceiptNum` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '杩?
娑璐ч棰,^MnReceiptCost` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '杩?
彖揣姘?,^MnDeliveryNum` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '杩?
彖揣殚?^MrnDeliveryCost` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '杩?
 ADD `useReturnNum` DOUBLE (16, 5) DEFAULT 0.00000 COMMENT '棰绋?
2018-08-06 21:16:13 19593 [Warning] Slave: Temporary file write failure. Error_code: 1878
2018-08-06 21:16:13 19593 [ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'mysql-bin.000810' position 137229440
2018-08-06 21:30:18 7fcb3cad7700 InnoDB: Error: Write to file (merge) failed at offset 31847350272.
InnoDB: 1048576 bytes should have been written, only 978944 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.6/en/operating-system-error-codes.html

报空间不错
用show variables like '%tmpdir%';查看tmpdir指向    /tmp在 
但系统的根目录/ 总的大小为40G

修改tmpdir 执行大的目录,这个参数不能在线修改,添加参数到参数文件里重启mysql数据库
tmpdir =/data/tmp

再次开启复制 start slave;
执行到00:51时候报错,mysql 挂掉了InnoDB: Error: Write to file
Next activation : never
2018-08-06 23:21:52 3588 [Warning] IP address '183.159.182.171' could not be resolved: Name or service not known
2018-08-06 23:22:21 3588 [Warning] IP address '118.31.44.222' could not be resolved: Name or service not known
2018-08-06 23:36:51 3588 [Warning] IP address '58.100.103.136' could not be resolved: Name or service not known
2018-08-07 00:51:45 7fc519552700 InnoDB: Error: Write to file ./ybl_erp/#sql-ib1166.ibd failed at offset 35306602496.
InnoDB: 1048576 bytes should have been written, only 307200 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.6/en/operating-system-error-codes.html
16:51:45 UTC - mysqld got signal 11 ;
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.
We will try our best to scrape up some info that will hopefully help
diagnose the problem, but since we have already crashed,
something is definitely wrong and this may fail.

具体原因位置,还是添加字段写临时的表时候报错,看来这个备库正常执行是不行了

启动mysql 
有这张大表的数据不是实时变化的,只有在每天23:59:59秒插入数据
所以现在
1.情况大表数据(truncate table)
2.开启复制把添加字段的语句同步过来(start slave)
3.关闭复制,单独迁移主库大表数据到自己备库上来(用阿里云的DTS迁移单表3600w 大概需要94分钟)
注意点迁移的时候备库的binglog日志没有关闭,如果关闭了速度会更快,另外迁移的过程需要关注binlog日志的大小以及及时清空binlog日志产生大概50G左右的日志防止把空间撑爆
4.迁移完成后需要删除添加字段以后添加的数据
5.启动复制进程(start slave)
6.观察复制正常

注意:(如果是表数据要是实时变化的用此种方法不行的)

可以使用
1.首先在自建备份库把表名字改了
2.然后新建表结构一样表
3.开启同步把添加字段的语句同步过来(或者新建的表已经包含添加的字段了)
4.把备份数据迁移回去
5.开启复制进程
没有采用此方法的原因是因为我的磁盘空不够,因为这样需要大表两倍以上的空间才能操作

大表添加字段要考虑
1.检查是否有足够空间
2.测试评估需要多长时间
3.考虑备库的复制延迟
直接alter table容易锁表
并发系统直接alter table易出现拿不到锁,导致server Crash
MySQL 5.6 持在线的online ddl,但容易造成复制延迟
对于alter table操作,请查看每个版本,确认只是更改字典信息,copy可以在线操作
拿不准情况推荐: pt-osc
mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: rm-bp1q8m0fbf5sjpl11ii.mysql.rds.aliyuncs.com
                  Master_User: rplslave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000813
          Read_Master_Log_Pos: 176958300
               Relay_Log_File: relay-bin.000344
                Relay_Log_Pos: 176958470
        Relay_Master_Log_File: mysql-bin.000813
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 176958300
              Relay_Log_Space: 176958755
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 985930441
                  Master_UUID: 9c182817-050c-11e8-be72-7cd30ae00a0e
             Master_Info_File: /data/mysqldata/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 9c182817-050c-11e8-be72-7cd30ae00a0e:10322657-16590246
            Executed_Gtid_Set: 2a02886b-9373-11e7-99b0-7cd30ac33424:1-49891487,
9c182817-050c-11e8-be72-7cd30ae00a0e:1-16590246,
cabfbbf6-7ea0-11e8-bf60-00163e11a4fe:1-213319
                Auto_Position: 1

<think>好的,我需要帮助用户解决数据只读无法修改字段值的问题。首先,我得确认用户遇到的具体情况。用户提到数据是只读的,无法修改字段值,这可能由多种原因引起。我需要回忆常见的导致数据只读的因素,并组织成清晰的解答步骤。 首先,权限问题是最常见的原因之一。数据用户可能没有UPDATE权限。这时候应该检查用户的权限设置,确认是否有GRANT UPDATE的权限。需要指导用户如何查看和修改权限,比如使用SHOW GRANTS或者查询系统如information_schema.table_privileges。 接下来是数据的只读模式设置。比如MySQL的全局read_only变量或SQL Server的ALTER DATABASE SET READ_ONLY。如果数据被设置为只读模式,自然无法修改数据。需要提醒用户检查这些设置,并给出相应的修改命令,比如SET GLOBAL read_only=0。 锁或事务未提交也可能导致被锁定,无法写入。这时候需要检查是否有未提交的事务或者长时间运行的查询占用了锁。可以建议用户查看INNODB_TRX或使用SHOW PROCESSLIST来识别和终止阻塞的进程。 存储引擎的问题也不容忽视。比如MyISAM在损坏时可能会进入只读状态,需要修复。用户可能需要运行REPAIR TABLE命令。此外,磁盘空间不足或文件系统权限错误也可能导致无法写入,需要检查磁盘空间和文件权限。 如果是云数据,比如AWS RDS阿里云,可能有只读实例的情况。需要确认用户是否误连到了只读副本,建议检查连接配置并切换到主实例。 视图或触发器限制也是一个可能性。如果用户操作的是视图而非基,或者有触发器阻止更新,需要检查结构和相关触发器,确认是否有逻辑限制。 最后,应用程序层面的限制,比如框架配置或ORM设置,可能错误地设置了只读模式。需要检查应用配置文件,确保数据连接字符串没有readOnly参数。 总结时,应该提供一个清晰的解决步骤,帮助用户逐一排查可能的原因。同时,提醒用户在生产环境中操作前份数据,避免误操作导致数据丢失。需要保持回答的结构清晰,分点说明每个可能的原因及解决方法,让用户能够逐步检查和解决问题。</think>当数据处于只读状态导致无法修改字段值时,通常由以下原因及解决方案构成: --- ### 一、常见原因及排查步骤 #### 1. **权限不足** - **现象** SQL执行报错如 `ERROR 1142 (42000): UPDATE command denied`。 - **检查方法** ```sql -- MySQL查看用户权限 SHOW GRANTS FOR '当前用户'@'主机'; -- 或查询系统 SELECT * FROM information_schema.table_privileges WHERE table_name = '名' AND grantee LIKE '%当前用户%'; ``` - **解决方案** 授权UPDATE权限: ```sql GRANT UPDATE ON 数据.名 TO '用户名'@'主机'; FLUSH PRIVILEGES; ``` #### 2. **数据/被显式设为只读** - **全局只读模式(MySQL示例)** 通过 `read_only` 参数控制: ```sql -- 检查设置 SHOW VARIABLES LIKE 'read_only'; -- 关闭只读(需SUPER权限) SET GLOBAL read_only = 0; ``` - **级只读(SQL Server示例)** 若被设为 `READ_ONLY`: ```sql -- 检查状态 SELECT is_read_only FROM sys.tables WHERE name = '名'; -- 修改为可写 ALTER TABLE 名 SET (READ_ONLY = OFF); ``` #### 3. **存储空间或文件系统问题** - **检查磁盘空间** ```bash # Linux查看磁盘使用率 df -h ``` - **修复(MyISAM引擎)** ```sql REPAIR TABLE 名; ``` - **检查文件权限** 确认数据文件(如 `.ibd`、`.myd`)的所属用户和权限: ```bash ls -l /var/lib/mysql/数据名/.ibd chmod 660 .ibd # 示例权限调整 ``` #### 4. **事务或锁阻塞** - **检查未提交事务(InnoDB)** ```sql SELECT * FROM information_schema.INNODB_TRX; ``` - **终止阻塞进程** ```sql KILL 进程ID; -- 根据INNODB_TRX结果操作 ``` #### 5. **云数据的只读副本** - **现象** 云服务(如AWS RDS阿里云)的只读实例拒绝写操作。 - **解决方案** 确保连接到主实例而非只读副本,检查连接地址配置。 --- ### 二、代码层验证示例 若问题与程序逻辑相关,可通过直接执行SQL测试: ```sql -- 尝试手动更新(验证是否报错) BEGIN; UPDATE 名 SET 字段 = 新值 WHERE 条件; ROLLBACK; -- 测试后回滚 ``` - 若手动执行成功 → 问题在应用程序(如ORM配置或连接池权限)。 - 若手动执行失败 → 问题在数据本身。 -- ### 三、特殊场景处理 #### 1. **视图(View)误操作** - 确认操作对象是基而非视图: ```sql SHOW CREATE TABLE 名; -- 检查是否为VIEW ``` #### 2. **触发器(Trigger)拦截** - 检查是否有BEFORE UPDATE触发器强制回滚: ```sql SHOW TRIGGERS LIKE '名'; ``` --- ### 四、总结流程 1. **权限检查** → 2. **只读模式确认** → 3. **存储/文件系统排查** → 4. **锁/事务分析** → 5. **云服务配置验证** → 6. **代码层测试**。 若仍无法解决,建议提供具体数据类型(如MySQL、PostgreSQL)及错误日志,以便进一步诊断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值