dbstructsync 多套mysql环境表、字段、索引的差异sql产出(原创)
最近写了一个工具(比较两套测试环境mysql数据库中表、表字段、索引的差异,基于python)通过文章简单介绍下工具的相关内容
- 工具名称
- 主要功能
- 具体使用方法
- 部分实现代码
- 后续
一、工具名称:
dbstructsync (python库)
二、主要功能:
比较两套环境中mysql指定库中表、表字段及索引的差异,返回同步的sql ,里面包含建表,修改索引,修改字段的sql .
A环境的数据库db 作为sourcedb, B环境的数据库db targetdb ,程序逻辑比较的是 sourcedb 与targetdb 的差异,然后返回一个list的数据类型
list中包含新建表sql,修改、增加字段sql, 删除、新增索引sql
现在总共有3个版本,0.0.1 和0.0.2 存在一定的bug, 所以请使用最新的0.0.3版本

其他说明:由于是刚完成不久的程序,所以暂时不对最终结果sql进行执行,避免对使用过程中产生不好的影响,这个版本大家可以通过python 自行选择需要执行哪些操作;随着之后程序的逐步深入修改和演变,会将执行sql这一步也都加进去
同时也会优化使用方式,让使用这个工具的小伙伴更容易操作
三、具体使用方法:
1、 pip install -i https://pypi.python.org/pypi dbstructsync
在代码里引入使用,
from DbStructSync import cli result=cli.db_sync(sourcedb, targetdb)
#sourcedb,targetdb是两个dict的参数,具体参数看下面
# 这里得到的 result = ['use 库;',
# 'CREATE TABLE `test_async` (\n `test_async` #varchar(30) NOT NULL,\n `aa` varchar(400) DEFAULT NULL,\n #PRIMARY KEY (`test_async`)\n) ENGINE=InnoDB DEFAULT #CHARSET=utf8;',
# 'drop index `index_chaxx` on chanxx_auto_puxx_conf;',
# 'create index `index_chaxx` on #chanxx_auto_puxx_conf(`channel_nxx`,`channel_prxx`) USING #BTREE;']
#result 中包含 use 库;
# 如果有少的表,会有 create table的数据; 如果有不同的索引,会#存在drop index 和create index的sql;
# 如果有不同的字段,会有alter table的sql ;
#只需要对这个结果,再通过pymysql的一些数据库操作就可以保证 sourcedb #的内容与taragetdb一致。
2、同时还支持命令行操作,代码写入到x.py代码中
result = cli.db_sync_commandline()
python x.py --source host=10.1.1.x,port=3306,user=root,passwd=root,db=investx --target host=10.1.1.x,port=3306,user=root,passwd=root,db=investx
命令行中 --source key=value;key2=value2;key3=value3 --target key=value;key2=value2;key3=value3
--source, --target 是两给必输的参数,后续的值会作为一个dict类型传入程序。 --source是源库的信息, --target是目标库的信息
还包括其他几个命令参数 --only-index , --only-fields ; --only-index 只比较索引差异, --only-fields 只比较字段差异, 非必填,默认都为False
四、部分实现代码:
def diff_tables(sourcetable, targettable):
''' :param sourcetable: 源数据库的表名列表
:param targettable: 目的数据库的表名列表
:return: 返回dict,包含三种结果,源库多的表,目标库多的表,相同的表
'''
logger.info('开始比较两个库中表的差异,源库表{},目标库表{}'.format(sourcetable, targettable))
table_result={}
if not isinstance(sourcetable, list) or not isinstance(targettable, list):
raise TypeError('sourcetable , targettable的类型不是list')
source_diff = set(sourcetable) - set(targettable)
target_diff = set(targettable) - set(sourcetable)
same_tables = set(sourcetable)& set(targettable)
table_result['source'] = source_diff
table_result['target'] = target_diff
table_result['same'] = same_tables
logger.info('两个库中表的差异结果{}'.format(table_result))
return table_result def diff_indexs_fields(sourcesql, targetsql, type=1):
'''
:param sourcesql: 源数据库表的创建sql
:param targetsql: 目标数据表的创建sql
:return: 记录下索引不一致的地方
'''
result = {}
logger.info('解析语句中的索引字段,并进行比较索引')
sourcesql = parse_str(sourcesql) # 从括号中提取需要的内容
#logger.info('从括号中提取出来的信息数据{}'.format(sourcesql))
sourcesql = lists2str(sourcesql) #将list转换为str,并对数据的空格数据进行处理
logger.info('解析完的数据的信息{}'.format(sourcesql))
sourcesql = sourcesql.split('\n') #将str按照'\\n'进行分割
logger.info('解析完数据之后的信息{}'.format(sourcesql))
targetsql = parse_str(targetsql)
targetsql = lists2str(targetsql)
targetsql = targetsql.split('\n')
if type ==1:
source_index = parse_fields(sourcesql,type)
target_index = parse_fields(targetsql,type) result= compare_indexs_field(source_index, target_index, type)
elif type ==2:
source_field_sql = parse_fields(sourcesql, type)
target_field_sql = parse_fields(targetsql, type)
result = compare_indexs_field(source_field_sql, target_field_sql, type)
return result def dict2sql(dict_str):
'''
将解析完成的数据转换为对应的可执行sql
:param dict_str:
:return:
'''
dict_str = copy.deepcopy(dict_str) # 做一个深度copy,可以放心的进行相关数据处理 if not isinstance(dict_str, dict):
raise TypeError('调用方法{}参数不是dict类型,请确认'.format('dict2sql'))
#获取db名字
for key ,value in dict_str.items():
dbname = key
logger.info('数据库名{}'.format(dbname))
for table, table_desc in value.get('source').items():
if table =='create_table':
#create_table_sql = lists2str(table_desc)
dict_str[dbname]['source'][table] = table_desc
#其他的都是table的名字
logger.info('数据库的修改语句:{}'.format(table_desc))
else:
logger.info('对于索引和字段的解析原始数据{}'.format(table_desc))
if table_desc.get('index'):
create_index_sql_lists=[]
#create_index_sql_lists.append('use {};'.format(dbname))
index_lists= (table_desc.get('index'))
result_index= parse_comma_split(str(index_lists)[1:-1])
for i in result_index:
if i.strip().startswith('\'KEY'):
#print(i.strip())
index_values = parse_space_split(i.strip())
drop_index_sql= 'drop index {} on {}'.format(index_values[1],table )
if len(index_values)<=3:
create_index_sql='create index {} on {}{} '.format(index_values[1], table, index_values[2])
else:
create_index_sql='create index {} on {}{} {}'.format(index_values[1], table, index_values[2], ' '.join(index_values[3:]))
create_index_sql_lists.append(drop_index_sql)
create_index_sql_lists.append(create_index_sql) if i.strip().startswith('\'UNIQUE KEY'):
index_values = parse_space_split(i.strip())
drop_index_sql = 'drop index {} on {}'.format(index_values[2], table)
if len(index_values) <= 4:
create_index_sql = 'create unique index {} on {}{} '.format(index_values[2], table,
index_values[3])
else:
create_index_sql = 'create unique index {} on {}{} {}'.format(index_values[2], table,
index_values[3],
' '.join(index_values[4:]),
)
create_index_sql_lists.append(drop_index_sql)
create_index_sql_lists.append(create_index_sql)
logger.info('表{}解析出来的索引的修改sql{}'.format(table, create_index_sql_lists))
dict_str[dbname]['source'][table]['index'] = create_index_sql_lists
if table_desc.get('fields'):
create_fields_sql_lists=[]
#create_fields_sql_lists.append('use {};'.format(dbname))
modify_field_sqls = table_desc.get('fields').get('modify',None)
create_field_sqls=table_desc.get('fields').get('lose',None) if modify_field_sqls:
for modify_field_sql in modify_field_sqls:
sql_indexs = parse_space_split(str(modify_field_sql)[0:-1])
#print(sql_indexs)
alter_fields_sql='alter table {} modify column {} {} {}'.format(table, sql_indexs[0],sql_indexs[1],' '.join(sql_indexs[2:]))
create_fields_sql_lists.append(alter_fields_sql)
if create_field_sqls:
for create_field_sql in create_field_sqls:
sql_indexs = parse_space_split(str(create_field_sql)[0:-1])
create_fields_sql='alter table {} add column {} {}'.format(table, sql_indexs[0],' '.join(sql_indexs[2:]))
create_fields_sql_lists.append(create_fields_sql)
logger.info('表{}解析出来的字段的修改sql{}'.format(table,create_fields_sql_lists))
dict_str[dbname]['source'][table]['fields'] = create_fields_sql_lists return dict_str # 返回给一个全部是可执行sql的dict
五、后续:
1、对使用过程中遇到对bug进行修复
2、对代码进行优化
3、增加其他相关功能,让工具越来越好用
4、希望使用的小伙伴多提意见,未来成为一个好用的小工具
dbstructsync 多套mysql环境表、字段、索引的差异sql产出(原创)的更多相关文章
- MySQL InnoDB表和索引之聚簇索引与第二索引
MySQL InnoDB表和索引之聚簇索引与第二索引 By:授客QQ:1033553122 每个InnoDB表都有一个称之为聚簇索引(clustered index)的特殊索引,存储记录行数据.通常, ...
- mysql创建表与索引
-- ---------------------------- -- 商品属性表 -- AUTO_INCREMENT=1为设置了自增长的字段设置起点,1为起点 -- ENGINE选择:MyISAM类型 ...
- MySQL查看表的索引【转】
查看表的索引: show index from table_name(表名) 结果列表中各字段的含义: · Non_unique 如果索引不能包括重复词,则为0.如果可以,则为1. · Key_nam ...
- 随笔编号-16 MySQL查看表及索引大小方法
目标:阿里云OS数据库DMS,单个主库最大存储空间为2T.最近公司业务扩展很快,一天数据量达到7.9G左右.要求备份清理历史数据,备份到其他磁盘. 准备: 如果想知道MySQL数据库中每个表占用的空间 ...
- MySQL 回表查询 & 索引覆盖优化
回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...
- Mysql 修改数据库,mysql修改表类型,Mysql增加表字段,Mysql删除表字段,Mysql修改字段名,Mysql修改字段排列顺序,Mysql修改表名
对于已经创建好的表,尤其是已经有大量数据的表,如果需要对表做一些结构上的改变,我们可以先将表删除(drop),然后再按照新的表定义重建表.这样做没有问题,但是必然要做一些额外的工作,比如数据的重新加载 ...
- mysql每个表总的索引大小
/* 指定的数据库 每个表的索引 不包含主键索引的大小*/ ,),,),'mb') as index_size from information_schema.tables where TABLE_S ...
- mysql alter修改字段的长度 类型sql语句
在mysql中alter命令可以修改字段类型,长度,名称或一些其它的参数,下面我来给大家介绍alter函数修改字段长度与类型的两个命令,希望文章来给各位带来帮助. mysql 修改字段长度 a ...
- Mysql建表+创建索引
创建表时可以直接创建索引,这种方式最简单.方便.其基本形式如下: CREATE TABLE 表名( 属性名 数据类型[完整性约束条件], 属性名 数据类型[完整性约束条件], ...... 属性名 数 ...
随机推荐
- netty中Pipeline的ChannelHandler执行顺序案例详解
一.netty的Pipeline模型 netty的Pipeline模型用的是责任链设计模式,当boss线程监控到绑定端口上有accept事件,此时会为该socket连接实例化Pipeline,并将In ...
- 7.HTTP协议
1.什么是url? 1.1 URL是统一资源定位符,表示的是一个资源,(图片 文字 视频 音频 等等) 单个资源介绍--图片 那URL的组成部分是由协议, 域名:端口, 路径和文件名 1.2 url组 ...
- jquery mutilselect 插件添加中英文自动补全
jquery mutilselect默认只能根据设置的option来进行自动提示 $.each(availableTags, function(key, value) { $('#channels') ...
- PHP安装amqp拓展(win环境)
安装php扩展amqp 先查看自己的php版本 记住版本 至于这个线程安全问题 这里引用了别人的自己看看吧 http://blog.csdn.net/aoyoo111/article/detail ...
- OptimalSolution(8)--位运算
一.不用额外变量交换两个整数的值 如果给定整数a和b,用以下三行代码即可交换a和b的值.a = a ^ b; b = a ^ b; a = a ^ b; a = a ^ b :假设a异或b的结果记为c ...
- hystrix原理
一.hystrix 产生背景 微服务是解决复杂服务的一个方案,在功能不变的情况下,对一个复杂的单体服务分解为多个可管理的分支.每个服务作为轻量的子服务,通过RPC实现服务间的关联,将服务简单化.每个服 ...
- GCC常用参数详解
转载:http://www.cnblogs.com/zhangsir6/articles/2956798.html 简介gcc and g++现在是gnu中最主要和最流行的c & c++编译器 ...
- Linux 编译与交叉编译
在Linux环境中,所处平台不同,执行文件也就不同,同一执行文件不能在不同平台下使用 如在Ubnutu下 是用gcc编译一个.c文件 gcc main.c -o main.out -o 可以指定输出文 ...
- Java 数据类型和初始值
Java 基本数据类型 byte.short.int.long.float.double.boolean.char byte 数据类型是8位.有符号的,以二进制补码表示的整数 short 数据类型是 ...
- H5 + WebGL 实现的楼宇自控 3D 可视化监控
前言 智慧楼宇和人们的生活息息相关,楼宇智能化程度的提高,会极大程度的改善人们的生活品质,在当前工业互联网大背景下受到很大关注.目前智慧楼宇可视化监控的主要优点包括: 智慧化 -- 智慧楼宇是一个生态 ...