#!/usr/bin/env python3 # -*- coding: utf-8 -*- """对比生产数据库和开发数据库的表结构一致性。""" import sys # 数据库连接配置 PROD_HOST = "124.221.143.140" DEV_HOST = "192.168.1.3" PORT = 8091 USER = "opc" PASSWORD = "jjjsgysyujkwjwgb" DB_NAME = "opc" PROD_URL = f"mysql+pymysql://{USER}:{PASSWORD}@{PROD_HOST}:{PORT}/{DB_NAME}?charset=utf8mb4" DEV_URL = f"mysql+pymysql://{USER}:{PASSWORD}@{DEV_HOST}:{PORT}/{DB_NAME}?charset=utf8mb4" print(f"生产数据库: {PROD_HOST}:{PORT}/{DB_NAME}") print(f"开发数据库: {DEV_HOST}:{PORT}/{DB_NAME}") print() from sqlalchemy import create_engine, inspect def get_db_structure(url): """获取数据库的完整结构信息。""" engine = create_engine(url, pool_pre_ping=True, connect_args={'connect_timeout': 10}) inspector = inspect(engine) structure = {} # 获取所有表 tables = inspector.get_table_names() structure['tables'] = sorted(tables) # 获取每个表的详细结构 table_details = {} for table in tables: cols = inspector.get_columns(table) col_info = {} for col in cols: col_info[col['name']] = { 'type': str(col['type']), 'nullable': col.get('nullable', True), 'default': str(col.get('default', '')), } # 获取主键 try: pk_constraint = inspector.get_pk_constraint(table) if isinstance(pk_constraint, dict): primary_key = pk_constraint.get('constrained_columns', []) else: primary_key = list(pk_constraint) if pk_constraint else [] except Exception: primary_key = [] table_details[table] = { 'columns': col_info, 'primary_key': primary_key, 'indexes': [(idx['name'], tuple(idx['column_names']), idx.get('unique', False)) for idx in inspector.get_indexes(table)], } structure['table_details'] = table_details engine.dispose() return structure def compare_structures(prod, dev): """对比两个数据库结构,返回差异列表。""" diffs = [] # 1. 对比表列表 prod_tables = set(prod['tables']) dev_tables = set(dev['tables']) only_in_prod = prod_tables - dev_tables only_in_dev = dev_tables - prod_tables if only_in_prod: diffs.append(f"⚠️ 仅在生产数据库存在的表 ({len(only_in_prod)}): {sorted(only_in_prod)}") if only_in_dev: diffs.append(f"⚠️ 仅在开发数据库存在的表 ({len(only_in_dev)}): {sorted(only_in_dev)}") # 2. 对比共有表的结构 common_tables = prod_tables & dev_tables for table in sorted(common_tables): prod_detail = prod['table_details'][table] dev_detail = dev['table_details'][table] # 对比列 prod_cols = set(prod_detail['columns'].keys()) dev_cols = set(dev_detail['columns'].keys()) cols_only_in_prod = prod_cols - dev_cols cols_only_in_dev = dev_cols - prod_cols if cols_only_in_prod: diffs.append(f" 📋 表 [{table}]: 仅在生产存在的列: {sorted(cols_only_in_prod)}") if cols_only_in_dev: diffs.append(f" 📋 表 [{table}]: 仅在开发存在的列: {sorted(cols_only_in_dev)}") # 对比共有列的属性 common_cols = prod_cols & dev_cols for col in sorted(common_cols): prod_col = prod_detail['columns'][col] dev_col = dev_detail['columns'][col] if prod_col['type'] != dev_col['type']: diffs.append(f" 🔧 表 [{table}].列 [{col}]: 类型不一致 - 生产={prod_col['type']}, 开发={dev_col['type']}") if prod_col['nullable'] != dev_col['nullable']: diffs.append(f" 🔧 表 [{table}].列 [{col}]: 可空性不一致 - 生产={prod_col['nullable']}, 开发={dev_col['nullable']}") # 对比主键 if prod_detail['primary_key'] != dev_detail['primary_key']: diffs.append(f" 🔑 表 [{table}]: 主键不一致 - 生产={prod_detail['primary_key']}, 开发={dev_detail['primary_key']}") # 对比索引 prod_indexes = set(prod_detail['indexes']) dev_indexes = set(dev_detail['indexes']) idx_only_in_prod = prod_indexes - dev_indexes idx_only_in_dev = dev_indexes - prod_indexes if idx_only_in_prod: diffs.append(f" 📊 表 [{table}]: 仅在生产存在的索引: {sorted(idx_only_in_prod)}") if idx_only_in_dev: diffs.append(f" 📊 表 [{table}]: 仅在开发存在的索引: {sorted(idx_only_in_dev)}") return diffs try: print("正在连接生产数据库...") prod_structure = get_db_structure(PROD_URL) print(f"✓ 生产数据库: {len(prod_structure['tables'])} 张表") print("正在连接开发数据库...") dev_structure = get_db_structure(DEV_URL) print(f"✓ 开发数据库: {len(dev_structure['tables'])} 张表") print() diffs = compare_structures(prod_structure, dev_structure) if not diffs: print("✅ 生产数据库和开发数据库结构完全一致!") else: print(f"❌ 发现 {len(diffs)} 处差异:") print() for diff in diffs: print(diff) # 输出表数量统计 print() print("=" * 60) print(f"表总数: 生产={len(prod_structure['tables'])}, 开发={len(dev_structure['tables'])}") print(f"共有表: {len(set(prod_structure['tables']) & set(dev_structure['tables']))}") # 重点检查新增的 compute_series 和 compute_icons 表 print() print("=" * 60) print("重点检查新增表:") for new_table in ['compute_series', 'compute_icons']: in_prod = new_table in prod_structure['tables'] in_dev = new_table in dev_structure['tables'] print(f" {new_table}: 生产={'✓' if in_prod else '✗'}, 开发={'✓' if in_dev else '✗'}") if in_prod and in_dev: prod_cols = list(prod_structure['table_details'][new_table]['columns'].keys()) dev_cols = list(dev_structure['table_details'][new_table]['columns'].keys()) print(f" 生产列 ({len(prod_cols)}): {prod_cols}") print(f" 开发列 ({len(dev_cols)}): {dev_cols}") except Exception as e: print(f"❌ 错误: {e}") import traceback traceback.print_exc() sys.exit(1)