# -*- coding: utf-8 -*- """ 删除 users.referred_by 冗余字段 优化绑定关系存储,只使用 referral_bindings 表 """ import pymysql import sys # 数据库配置(从 lib/db.ts 获取) DB_CONFIG = { 'host': 'gz-cynosdbmysql-grp-kfcvxbby.sql.tencentcdb.com', 'port': 27815, 'user': 'root', 'password': 'Aa112211', 'database': 'soul_miniprogram', 'charset': 'utf8mb4' } def print_step(step, msg): """打印步骤信息""" print('\n' + '=' * 70) print('步骤 {}: {}'.format(step, msg)) print('=' * 70) def execute_sql(cursor, sql, params=None): """执行SQL并返回影响行数""" try: if params: cursor.execute(sql, params) else: cursor.execute(sql) return cursor.rowcount except Exception as e: print('执行失败: {}'.format(str(e))) raise def main(): connection = None try: print_step(1, '连接数据库') connection = pymysql.connect(**DB_CONFIG) cursor = connection.cursor() print('已连接到数据库: {}'.format(DB_CONFIG['database'])) # ======================================== # 步骤2: 备份当前 referred_by 数据 # ======================================== print_step(2, '备份 referred_by 数据(用于验证)') cursor.execute(''' SELECT COUNT(*) as total, COUNT(referred_by) as has_referrer, COUNT(DISTINCT referred_by) as unique_referrers FROM users ''') stats = cursor.fetchone() print('当前用户表统计:') print(' 总用户数: {}'.format(stats[0])) print(' 有推荐人的用户: {}'.format(stats[1])) print(' 唯一推荐人数: {}'.format(stats[2])) # 导出 referred_by 数据到临时表(备份) cursor.execute('DROP TABLE IF EXISTS users_referred_by_backup') cursor.execute(''' CREATE TABLE users_referred_by_backup AS SELECT id, referred_by, created_at FROM users WHERE referred_by IS NOT NULL ''') backup_count = cursor.rowcount print('已备份 {} 条记录到 users_referred_by_backup 表'.format(backup_count)) # ======================================== # 步骤3: 验证 referral_bindings 数据完整性 # ======================================== print_step(3, '验证 referral_bindings 数据完整性') cursor.execute(''' SELECT COUNT(*) as total_bindings, COUNT(DISTINCT referee_id) as unique_referees, SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active_bindings FROM referral_bindings ''') binding_stats = cursor.fetchone() print('推荐绑定表统计:') print(' 总绑定记录: {}'.format(binding_stats[0])) print(' 唯一被推荐人: {}'.format(binding_stats[1])) print(' 当前活跃绑定: {}'.format(binding_stats[2])) # 检查数据一致性 cursor.execute(''' SELECT COUNT(*) FROM users u WHERE u.referred_by IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM referral_bindings rb WHERE rb.referee_id = u.id ) ''') inconsistent = cursor.fetchone()[0] if inconsistent > 0: print('警告: 发现 {} 个用户在 users.referred_by 有值但 referral_bindings 中无记录'.format(inconsistent)) print('这些记录可能是旧数据,删除字段后将丢失') else: print('数据一致性检查通过!') # ======================================== # 步骤4: 删除 referred_by 相关索引 # ======================================== print_step(4, '删除 referred_by 索引') # 检查索引是否存在 cursor.execute(''' SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = %s AND table_name = 'users' AND index_name = 'idx_referred_by' ''', (DB_CONFIG['database'],)) index_exists = cursor.fetchone()[0] > 0 if index_exists: cursor.execute('ALTER TABLE users DROP INDEX idx_referred_by') print('已删除索引: idx_referred_by') else: print('索引 idx_referred_by 不存在,跳过') # ======================================== # 步骤5: 删除 referred_by 字段 # ======================================== print_step(5, '删除 users.referred_by 字段') # 检查字段是否存在 cursor.execute(''' SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = %s AND table_name = 'users' AND column_name = 'referred_by' ''', (DB_CONFIG['database'],)) field_exists = cursor.fetchone()[0] > 0 if field_exists: cursor.execute('ALTER TABLE users DROP COLUMN referred_by') print('已删除字段: users.referred_by') else: print('字段 referred_by 不存在,跳过') # ======================================== # 步骤6: 提交更改 # ======================================== print_step(6, '提交数据库更改') connection.commit() print('所有更改已提交!') # ======================================== # 步骤7: 验证删除结果 # ======================================== print_step(7, '验证删除结果') cursor.execute(''' SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = %s AND table_name = 'users' AND column_name = 'referred_by' ''', (DB_CONFIG['database'],)) still_exists = cursor.fetchone()[0] > 0 if still_exists: print('警告: 字段仍然存在!') else: print('验证通过: referred_by 字段已成功删除') # 检查备份表 cursor.execute('SELECT COUNT(*) FROM users_referred_by_backup') backup_rows = cursor.fetchone()[0] print('备份表保留了 {} 条记录(可选择稍后删除)'.format(backup_rows)) # ======================================== # 完成 # ======================================== print('\n' + '=' * 70) print('优化完成!') print('=' * 70) print('\n后续步骤:') print('1. 修改代码中所有使用 referred_by 的地方') print('2. 部署新代码到服务器') print('3. 测试绑定和佣金功能') print('4. 确认无误后,可删除备份表: DROP TABLE users_referred_by_backup') print('\n备份表可保留一段时间,确保数据安全。') except Exception as e: print('\n错误: {}'.format(str(e))) if connection: connection.rollback() print('已回滚所有更改') sys.exit(1) finally: if connection: cursor.close() connection.close() print('\n数据库连接已关闭') if __name__ == '__main__': print('\n' + '=' * 70) print('删除 users.referred_by 冗余字段') print('=' * 70) print('\n此脚本将执行以下操作:') print('1. 备份 referred_by 数据到 users_referred_by_backup 表') print('2. 删除 idx_referred_by 索引') print('3. 删除 users.referred_by 字段') print('\n警告: 此操作会修改数据库结构!') print('建议先在测试环境执行。') try: raw_input_func = raw_input # Python 2 except NameError: raw_input_func = input # Python 3 confirm = raw_input_func('\n确认执行?(输入 yes 继续): ') if confirm.lower() != 'yes': print('已取消操作') sys.exit(0) main()