玖叶教程网

前端编程开发入门

mysql大表加减列及索引(mysql 大表加索引)

由于对于大表增加,减少列或索引都会锁库不能直接在原表上操作,所以使用pt-online-schema-change工具进行处理,也是尽量在无业务的时候处理。

1、pt-online-schema-change工具

1.1、pt-online-schema-change工具安装

1.1.1、查看是否安装依赖

rpm -qa perl-DBI perl-DBD-MySQL perl-Time-HiRes perl-IO-Socket-SSL perl-TermReadKey perl-Digest-MD5

1.1.2、安装依赖

yum -y install perl-DBI perl-DBD-MySQL perl-Time-HiRes perl-IO-Socket-SSL perl-TermReadKey perl-Digest-MD5

1.1.3、下载

wget -c https://www.percona.com/downloads/percona-toolkit/3.1.0/binary/redhat/7/x86_64/percona-toolkit-3.1.0-2.el7.x86_64.rpm

1.1.4、安装

rpm -ivh percona-toolkit-3.1.0-2.el7.x86_64.rpm

1.2、操作步骤

2.1、创建一个和要执行 alter 操作的表一样的新的空表结构(是alter之前的结构)

2.2、在新表执行alter table 语句(速度应该很快)

2.3、在原表中创建触发器3个触发器分别对应insert,update,delete操作

2.4、以一定块大小从原表拷贝数据到临时表,拷贝过程中通过原表上的触发器在原表进行的写操作都会更新到新建的临时表

2.5、Rename 原表到old表中,在把临时表Rename为原表

2.6、如果有参考该表的外键,根据alter-foreign-keys-method参数的值,检测外键相关的表,做相应设置的处理

2.7、默认最后将旧原表删除

1.3、参数说明

1.3.1、--host=xxx --user=xxx --password=xxx

连接实例信息,缩写-h xxx -u xxx -p xxx,密码可以使用参数--ask-pass 手动输入。

1.3.2、--alter

指定ALTER 语句,正常的ALTER TABLE TBNAME [ ADD | MODIFY | DROP | ALTER ] COLUMN COLUMN_NAME ...,去除前面的ALTER TABLE TABLE那么,直接指定后部分的内容

注意事项:

rename不支持,请直接使用RENAME TABLE tablename TO new_tablename;

如果表格有数据,创建非空无默认值的列,会失败,如果非空,需要指定默认值;

如果表格有数据,为一个可空的列添加默认值时,旧数据为NULL的是不会被修改,依旧为NULL,以后新加入到数据则会默认为设置的默认值

对于外键的删除情况,由于执行是在新表上执行DDL,所以其外键值的命名跟原表的命名不一样,假设删除原表的外键名是 fk_foo,那么新表的外键名就为 _fk_foo,所以删除的ALTER语句是: drop foreign key _fk_foo;

1.3.3、--alter-foreign-keys-method

如果修改的表格,是其他表格外键reference的表格,那么,最后rename的过程,需要确保一定成功,要不然这些子表就没能成功reference到其指定的表格名,对子表的操作将会报错。比如 tba有一个外键 fk_tba引用表格 tbb,这个时候tbb需要做DDL操作,根据pt工具的原理得知,最后会有一个rename环节,这个环节可能会导致约束失效或者执行堵塞等问题。

1.3.4、auto

自动选择 rebuild_constraints 或者 drop_swap,优先选择rebuild_constraints

1.3.5、rebuild_constraints

rename table 前,先删除子表的外键约束,然后重建外键约束指向到新表(ALTER TABLE语句添加),最后执行rename操作

这个rename操作即使不成功,它也rename到新表,不会出现reference的表格不存在情况

弊端:如果子表过大,添加外键约束的过程中,可能会对子表造成堵塞

1.3.6、drop_swap

执行rename之前禁用外键检查,然后删除原表,rename新表为原表名

这个过程非常快并且没有堵塞

这个方法需要强制指定 --no-swap-tables 跟 --no-drop-old-table.

弊端:当把原表删除而新表还没rename为原表的名字时,这段时间实际非常短,但是这段时间内,等于原表名的表格时不存在的,子表做一些DML的时候,可能会出现错误。rename期间,如果新表rename原表失败,但是已经删除原表,那么这段期间,其子表的操作将会出现大面积问题,直到人工修复

1.3.7、none

类似drop_swap操作,不同在于对原表的处理。

按正常的pt工具流程,禁用外键约束,rename原表为临时表,rename新表为原表名,删除临时表

弊端: 当把原表rename为临时表,而新表还没rename为原表的名字时,这段时间实际非常短,但是这段时间内,等于原表名的表格时不存在的,子表做一些DML的时候,可能会出现错误

1.3.8、--drop-old-table

操作成功后,原表是否保留,默认是删除,

default:yes,可选:--no-drop-old-table

D=db_name,t=table_name

指定要ddl的数据库名和表名

1.3.9、--no-drop-old-table

不删除旧表,旧表表名为 _表名_old

1.3.10、--max-load

默认为Threads_running=25。每个chunk拷贝完后,会检查 SHOW GLOBAL STATUS 的内容,检查指标是否超过了指定的阈值。如果超过,则先暂停。这里可以用逗号分隔,指定多个条件,每个条件格式: status指标=MAX_VALUE或者status指标:MAX_VALUE。如果不指定MAX_VALUE,那么工具会这只其为当前值的120%。

因为拷贝行有可能会给部分行上锁,Threads_running 是判断当前数据库负载的绝佳指标。

1.3.11、--max-lag

默认1s。每个chunk拷贝完成后,会查看所有复制Slave的延迟情况(Seconds_Behind_Master)。要是延迟大于该值,则暂停复制数据,直到所有从的滞后小于这个值。--check-interval配合使用,指定出现从库滞后超过 max-lag,则该工具将睡眠多长时间,默认1s,再检查。如--max-lag=5 --check-interval=2。

熟悉percona-toolkit的人都知道--recursion-method 可以用来指定从库dsn记录。另外,如果从库被停止,将会永远等待,直到从开始同步,并且延迟小于该值。

1.3.12、--chunk-time

默认0.5s,即拷贝数据行的时候,为了尽量保证0.5s内拷完一个chunk,动态调整chunk-size的大小,以适应服务器性能的变化。

也可以通过另外一个选项--chunk-size禁止动态调整,即每次固定拷贝 1k 行,如果指定则默认1000行,且比 chunk-time 优先生效

1.3.13、--set-vars

使用pt-osc进行ddl要开一个session去操作,set-vars可以在执行alter之前设定这些变量,比如默认会设置--set-vars "wait_timeout=10000,innodb_lock_wait_timeout=1,lock_wait_timeout=60"。

因为使用pt-osc之后ddl的速度会变慢,所以预计2.5h只能还不能改完,记得加大wait_timeout。

1.3.14、--dry-run

创建和修改新表,但不会创建触发器、复制数据、和替换原表。并不真正执行,可以看到生成的执行语句,了解其执行步骤与细节,和--print配合最佳。

1.3.15、--execute

确定修改表,则指定该参数。真正执行alter。--dry-run与--execute必须指定一个,二者相互排斥

1.3.16、--charset=utf8

使用utf8编码,避免中文乱码

1.3.17、--no-version-check

不检查版本,在阿里云服务器中一般加入此参数,否则会报错

1.4、实际操作

1.4.1、增加批处理文件pt.sh,并修改数据库连接

#!/bin/bash 
table=$1 alter_conment=$2 
cnn_host='192.9.200.227' 
cnn_port=3306 
cnn_user='root' 
cnn_pwd='123456' 
cnn_db='bladex' 
echo "$table" 
echo "$alter_conment" 
pt-online-schema-change --charset=utf8 --no-version-check --no-check-alter --no-check-replication-filters --user=${cnn_user} --password=${cnn_pwd} h=${cnn_host},P=${cnn_port},D=${cnn_db},t=$table --alter "${alter_conment}" --print --execute

1.4.2、增加列

数据库语句:ALTER TABLE `tb_test` ADD COLUMN `column1` tinyint(4) DEFAULT NULL;

命令:sh pt.sh tb_test "ADD COLUMN column1 tinyint(4) DEFAULT NULL"

1.4.3、修改列

数据库语句:ALTER TABLE `tb_test` MODIFY COLUMN `num` int(11) unsigned NOT NULL DEFAULT '0';

命令:sh pt.sh tb_test "MODIFY COLUMN num int(10) unsigned NOT NULL DEFAULT '0'"

1.4.4、修改字段名:要加--no-check-alter

数据库语句:ALTER TABLE `tb_test` CHANGE COLUMN num age varchar(30);

命令:sh pt.sh tb_test "CHANGE COLUMN num age varchar(30)"

1.4.5、添加删除索引:

数据库语句:ALTER TABLE `tb_test` ADD INDEX idx_age(age),DROP INDEX idx_name;

命令:sh pt.sh tb_test "ADD INDEX idx_age(age),DROP INDEX idx_name"

1.4.6、更换表引擎:(可以使用下面语句进行碎片整理,不锁表)

数据库语句:alter table tb_test engine=innodb

命令:sh pt.sh tb_test "ENGINE=InnoDB"

1.5、测试结果

开发测试可以,比较慢。

1.6、错误示例

You do not have the PROCESS privilege at /bin/pt-online-schema-change line 4421.

需要数据库授PROCESS权限

2、使用algorithm=INPLACE, lock=NONE

例:ALTER TABLE crm_consume DROP INDEX index_tenant_id, algorithm=INPLACE, lock=NONE;

注:如果是加字段的时候,数据量大,且在insert,update等DML执行时,可能会报如下错误:

Error 1062: Duplicate entry '1505727425870401538' for key 'PRIMARY'

原因: Oline DDL的原理简单一点理解就是将DML操作缓存起来,等到DDL执行完成后重新应用缓存中的DML语句,如果在Oline DDL执行过程中,DML操作产生了Duplicate entry错误,并不会直接影响DDL操作,而是在DDL执行完成最终应用DML时报错,导致DDL执行失败。官方认为该问题是一种限制,并不是Bug,所以目前为止还没有得到解决。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言