最近写了一个工具(比较两套测试环境mysql数据库中表、表字段、索引的差异,基于python)通过文章简单介绍下工具的相关内容

  1. 工具名称
  2. 主要功能
  3. 具体使用方法
  4. 部分实现代码
  5. 后续

一、工具名称:

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产出(原创)的更多相关文章

  1. MySQL InnoDB表和索引之聚簇索引与第二索引

    MySQL InnoDB表和索引之聚簇索引与第二索引 By:授客QQ:1033553122 每个InnoDB表都有一个称之为聚簇索引(clustered index)的特殊索引,存储记录行数据.通常, ...

  2. mysql创建表与索引

    -- ---------------------------- -- 商品属性表 -- AUTO_INCREMENT=1为设置了自增长的字段设置起点,1为起点 -- ENGINE选择:MyISAM类型 ...

  3. MySQL查看表的索引【转】

    查看表的索引: show index from table_name(表名) 结果列表中各字段的含义: · Non_unique 如果索引不能包括重复词,则为0.如果可以,则为1. · Key_nam ...

  4. 随笔编号-16 MySQL查看表及索引大小方法

    目标:阿里云OS数据库DMS,单个主库最大存储空间为2T.最近公司业务扩展很快,一天数据量达到7.9G左右.要求备份清理历史数据,备份到其他磁盘. 准备: 如果想知道MySQL数据库中每个表占用的空间 ...

  5. MySQL 回表查询 & 索引覆盖优化

    回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...

  6. Mysql 修改数据库,mysql修改表类型,Mysql增加表字段,Mysql删除表字段,Mysql修改字段名,Mysql修改字段排列顺序,Mysql修改表名

    对于已经创建好的表,尤其是已经有大量数据的表,如果需要对表做一些结构上的改变,我们可以先将表删除(drop),然后再按照新的表定义重建表.这样做没有问题,但是必然要做一些额外的工作,比如数据的重新加载 ...

  7. mysql每个表总的索引大小

    /* 指定的数据库 每个表的索引 不包含主键索引的大小*/ ,),,),'mb') as index_size from information_schema.tables where TABLE_S ...

  8. mysql alter修改字段的长度 类型sql语句

    在mysql中alter命令可以修改字段类型,长度,名称或一些其它的参数,下面我来给大家介绍alter函数修改字段长度与类型的两个命令,希望文章来给各位带来帮助.     mysql 修改字段长度 a ...

  9. Mysql建表+创建索引

    创建表时可以直接创建索引,这种方式最简单.方便.其基本形式如下: CREATE TABLE 表名( 属性名 数据类型[完整性约束条件], 属性名 数据类型[完整性约束条件], ...... 属性名 数 ...

随机推荐

  1. 3.1 C语言_实现AVL平衡二叉树

    [序] 上节我们实现了数据结构中最简单的Vector,那么来到第三章,我们需要实现一个Set set的特点是 内部有序且有唯一元素值:同时各种操作的期望操作时间复杂度在O(n·logn): 那么标准的 ...

  2. 3. SOFAJRaft源码分析— 是如何进行选举的?

    开篇 在上一篇文章当中,我们讲解了NodeImpl在init方法里面会初始化话的动作,选举也是在这个方法里面进行的,这篇文章来从这个方法里详细讲一下选举的过程. 由于我这里介绍的是如何实现的,所以请大 ...

  3. LeetCode初级算法--设计问题01:Shuffle an Array (打乱数组)

    LeetCode初级算法--设计问题01:Shuffle an Array (打乱数组) 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:h ...

  4. JavaScript中valueOf、toString的隐式调用

    今天在群上有人问这样一个问题: 函数add可以实现连续的加法运算函数add语法如下add(num1)(num2)(num3)...;//注意这里是省略号哟,无限使用举例如下:add(10)(10)=2 ...

  5. 微信小程序--获取用户地理位置名称(无须用户授权)的方法

    准备 1.在http://lbs.qq.com/网站申请key 2.在微信小程序后台把apis.map.qq.com添加进request合法域名 效果 添加封装 /** * 发起网络请求 * @par ...

  6. lambda高级查询

    1.什么是lambda表达式:Lambda 表达式,是一种简化的匿名函数,可用于创建委托或表达式目录树.其次,也可以将 Lambda 表达式作为参数进行传递,或者将它作用于函数调用值调用后返回的一个函 ...

  7. Swagger Learing - Spring Boot 整合swagger

    学习了一下swagger. 这是编写的Demo 源码 https://github.com/AmberBar/Learning/tree/master/swagger-learning/swagger ...

  8. Knative 实战:如何在 Knative 中配置自定义域名及路由规则

    作者 | 元毅 阿里云智能事业群高级开发工程师 当前 Knative 中默认支持是基于域名的转发,可以通过域名模板配置后缀,但目前对于用户来说并不能指定全域名设置.另外一个问题就是基于 Path 和 ...

  9. (三)快速添加touch事件

    EasyTouch提供了类似UGUI的可视化点击事件,如button类似,此功能可以快速实现三维物体的旋转缩放.在场景中新建cube然后添加组件,输入quick会出现一下一个选项: quick dra ...

  10. 使用asp.net core 3.0 搭建智能小车1

    跟随.net core 3.0 一起发布的System.Device.Gpio 1.0已经可以让我们用熟悉的C#原汁原味的开发莓派上面的GPIO了.并且在 Iot.Device.Bindings这个包 ...