online ddl 工具之pt-online-schema-change封装
一、原理
目前InnoDB引擎是通过以下步骤来进行DDL的:
1 按照原始表(original_table)的表结构和DDL语句,新建一个不可见的临时表(tmp_table)
2 在原表上加write lock,阻塞所有更新操作(insert、delete、update等)
3 执行insert into tmp_table select * from original_table
4 rename original_table和tmp_table,最后drop original_table
5 释放 write lock。
我们可以看见在InnoDB执行DDL的时候,原表是只能读不能写的。
pt-online-schema-change工作原理:
如果表有外键,除非使用 --alter-foreign-keys-method 指定特定的值,否则工具不予执行。
1 创建一个和你要执行 alter 操作的表一样的空表结构。
2 执行表结构修改,然后从原表中的数据到copy到 表结构修改后的表,
3 在原表上创建触发器将 copy 数据的过程中,在原表的更新操作 更新到新表.
注意:如果表中已经定义了触发器这个工具就不能工作了。
4 copy 完成以后,用rename table 新表代替原表,默认删除原表。
二、依赖
1、操作的表必须有主键。
2、不能rename或者change否则会丢失当前列数据。
3、添加字段时只要有not null 就要加default ‘’默认值 否则会报错
三、mysqlha_osc.sh使用方法
[root@db72 liding]# ./mysqlha_osc.sh
help:
Please check your input!!!!
options:
-P port
-D databases name
-T type 1=--dry-run 2=--execute
-S Please input sql
Can not enter change and rename because Can cause changes to fail
if values not null Time must be added default '0'
内部已经将rename|change 禁用
mysqlha_osc.sh -P 3306 -D test -T 2 -S "alter table test add uname varchar(20) "
P:port。
D:database name。
T:两个参数 1=--dry-run 2=–execute。
S:sql语句,和数据库正常语法一样。
#!/bin/bash
# Author: [email protected]
# Date: 2016-04-27
# helpfunc shows the help info
function helpfunc(){
echo
echo "Please check your input!!!!"
echo "options:"
echo " -P port"
echo " -D databases name"
echo " -T type 1=--dry-run 2=--execute "
echo " -S Please input sql "
echo " Can not enter change and rename because Can cause changes to fail"
echo "if values not null Time must be added default '0'"
}
############################################
#get options in command line, cannot be palced in a function
if [ $# -lt 1 ] ;
then
helpfunc
exit 1
else
while getopts "P:D:T:S:s:" Option
do
case $Option in
P) port=$OPTARG;;
D) database=$OPTARG;;
T) type=$OPTARG;;
S) sql=$OPTARG;;
*) helpfunc; exit 1; ;;
esac
done
fi
check_user()
{
echo "the user is now $person, checkout to 'root' to continue"
}
check_running()
{
run=`netstat -antp|grep mysql|grep $port`
if [ -z "$run" ]; then
echo "mysql port $port is not running!"
exit -1
fi
}
function main(){
check_user
check_running
sock=/tmp/mysql"$port".sock
. /etc/dbbin/sh_lib/config.sh "/etc/dbbin/conf/mysql.cfg"
admin_user=""#自己定义
admin_pass=`getConfig "mysql" $admin_user`#自己定义
tname=`echo $sql|awk '{print $3}'`
SQL=`echo $sql|awk -F"$tname" '{print $2}'`
if echo $SQL | egrep -w "rename|change" ; then
helpfunc;
exit 1
else
if [ $type = 1 ] ;then
/usr/bin/pt-online-schema-change --user $admin_user --password $admin_pass --port $port --socket $sock --alter "$SQL" D=$database,t=$tname --dry-run --critical-load="Threads_running=200"
elif [ $type = 2 ] ;then
/usr/bin/pt-online-schema-change --user $admin_user --password $admin_pass --port $port --socket $sock --alter "$SQL" D=$database,t=$tname --execute --critical-load="Threads_running=200"
else
helpfunc;
exit 1
fi
fi
}
###############################
main