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 表名( 属性名 数据类型[完整性约束条件], 属性名 数据类型[完整性约束条件], ...... 属性名 数 ...
随机推荐
- 玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- 云计算 docker 容器部署
什么是docker容器: 容器就是在隔离的环境中运行的一个进程,如果进程停止,容器就会退出.隔离的环境拥有自己的系统文件,ip地址,主机名等kvm虚拟机,linux,系统文件 容器和虚拟化的区别 : ...
- Django 从零开始
Django在Python的web开发框架中属于重量级的框架,功能多而全,但是相对的体积和坑也会比较多,但是其实学习Python的web开发个人觉得Django其实会比Flask好上手,特别是0基础的 ...
- hash算法的应用
一.单词模式匹配 描述:单词模式字符串为“一二二一”,目标字符串为"苹果 香蕉 香蕉 苹果"则匹配成功 a=[1,2,2,1,1,3] b=['x','y','y','x','x' ...
- C和C++引用传递和数组传参引用
引用传递有两种传参方式,具体可参考文章 概括地讲,就是 *声明一个形参是指针,所以需要传递指针实参,对应的函数实现也应当遵循指针的语法.这种实现思路并不针对于C或者C++,因为它们都有指针,所以都可以 ...
- c#通过libreOffice实现 office文件转pdf文件
一.安装libreOffice 点击官网下载libreOffice 二.创建一个新的项目LibreOffice 创建一个新的项目,方便后面调用 添加下面代码 public class OfficeCo ...
- iOS开发高级分享 - iOS上的设备标识符和指纹
苹果认可的标识符 Apple提供了各种API,以方便用户识别各种用途: 通用标识符(UDID) 在iOS的早期,苹果公司提供了一个uniqueIdentifier财产上UIDevice-亲切地称为ud ...
- 在VMware下的Linux中的RAID10校验位算法下的磁盘管理
988年由加利福尼亚大学伯克利分校发表的文章首次提到并定义了RAID,当今CPU性能每年可提升30%-50%但硬盘仅提升7%,渐渐的已经成为计算机整体性能的瓶颈,并且为了避免硬盘的突然损坏导致数据丢失 ...
- super()函数的作用
1.super()调用父类方法,并重写>>>>>>减少代码量(Square类实现) 2.它允许您在子类中调用超类的方法. 这种情况的主要用例是扩展继承方法的功能. ...
- LVS 十种算法
LVS虚拟服务器是章文嵩在国防科技大学就读博士期间创建的,LVS可以实现高可用的.可伸缩的网络服务. LVS集群组成: 前端:负载均衡层 (一台或多台负责调度器构成) 中间:服务器群组层 (由一组 ...