#!/usr/bin/env node /** * 检查数据库表结构脚本 * 对比设计文档与实际表结构 */ const mysql = require('mysql2/promise'); const config = require('../config/env'); async function checkTableStructure() { let connection; try { console.log('🔍 开始检查数据库表结构...'); const dbConfig = { host: config.mysql.host, port: config.mysql.port, user: config.mysql.user, password: config.mysql.password, database: config.mysql.database, charset: config.mysql.charset || 'utf8mb4', timezone: config.mysql.timezone || '+08:00' }; connection = await mysql.createConnection(dbConfig); console.log('✅ 数据库连接成功'); // 检查所有表的详细结构 const [tables] = await connection.execute( `SELECT table_name FROM information_schema.tables WHERE table_schema = ? ORDER BY table_name`, [dbConfig.database] ); console.log(`\n📊 数据库 ${dbConfig.database} 中共有 ${tables.length} 个表:`); for (const table of tables) { const tableName = table.TABLE_NAME || table.table_name; console.log(`\n🔍 检查表: ${tableName}`); // 获取表结构 const [columns] = await connection.execute( `SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_KEY, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE table_schema = ? AND table_name = ? ORDER BY ORDINAL_POSITION`, [dbConfig.database, tableName] ); // 获取表记录数 const [countResult] = await connection.execute(`SELECT COUNT(*) AS count FROM ${tableName}`); const recordCount = countResult[0].count; console.log(` 📊 记录数: ${recordCount}`); console.log(` 📋 字段结构 (${columns.length} 个字段):`); columns.forEach(col => { const nullable = col.IS_NULLABLE === 'YES' ? 'NULL' : 'NOT NULL'; const key = col.COLUMN_KEY ? `[${col.COLUMN_KEY}]` : ''; const extra = col.EXTRA ? `[${col.EXTRA}]` : ''; const defaultVal = col.COLUMN_DEFAULT !== null ? `DEFAULT: ${col.COLUMN_DEFAULT}` : ''; const comment = col.COLUMN_COMMENT ? `// ${col.COLUMN_COMMENT}` : ''; console.log(` - ${col.COLUMN_NAME}: ${col.DATA_TYPE} ${nullable} ${key} ${extra} ${defaultVal} ${comment}`); }); // 获取索引信息 const [indexes] = await connection.execute( `SELECT INDEX_NAME, COLUMN_NAME, NON_UNIQUE, INDEX_TYPE FROM information_schema.STATISTICS WHERE table_schema = ? AND table_name = ? ORDER BY INDEX_NAME, SEQ_IN_INDEX`, [dbConfig.database, tableName] ); if (indexes.length > 0) { console.log(` 🔑 索引信息:`); const indexGroups = {}; indexes.forEach(idx => { if (!indexGroups[idx.INDEX_NAME]) { indexGroups[idx.INDEX_NAME] = { columns: [], unique: idx.NON_UNIQUE === 0, type: idx.INDEX_TYPE }; } indexGroups[idx.INDEX_NAME].columns.push(idx.COLUMN_NAME); }); Object.entries(indexGroups).forEach(([indexName, info]) => { const uniqueStr = info.unique ? '[UNIQUE]' : ''; console.log(` - ${indexName}: (${info.columns.join(', ')}) ${uniqueStr} [${info.type}]`); }); } } // 检查外键约束 console.log(`\n🔗 检查外键约束:`); const [foreignKeys] = await connection.execute( `SELECT TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME, CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE table_schema = ? AND REFERENCED_TABLE_NAME IS NOT NULL ORDER BY TABLE_NAME, COLUMN_NAME`, [dbConfig.database] ); if (foreignKeys.length > 0) { foreignKeys.forEach(fk => { console.log(` - ${fk.TABLE_NAME}.${fk.COLUMN_NAME} -> ${fk.REFERENCED_TABLE_NAME}.${fk.REFERENCED_COLUMN_NAME} [${fk.CONSTRAINT_NAME}]`); }); } else { console.log(' ⚠️ 未发现外键约束'); } // 检查表大小 console.log(`\n💾 检查表存储大小:`); const [tableSizes] = await connection.execute( `SELECT table_name, ROUND(((data_length + index_length) / 1024 / 1024), 2) AS 'size_mb', table_rows FROM information_schema.tables WHERE table_schema = ? ORDER BY (data_length + index_length) DESC`, [dbConfig.database] ); tableSizes.forEach(size => { console.log(` - ${size.table_name}: ${size.size_mb} MB (${size.table_rows} 行)`); }); console.log('\n🎉 表结构检查完成!'); return { success: true, tableCount: tables.length, foreignKeyCount: foreignKeys.length }; } catch (error) { console.error('❌ 检查表结构失败:', error.message); return { success: false, error: error.message }; } finally { if (connection) { await connection.end(); console.log('🔒 数据库连接已关闭'); } } } // 如果是直接运行此文件,则执行检查 if (require.main === module) { checkTableStructure() .then((result) => { process.exit(result.success ? 0 : 1); }) .catch(() => process.exit(1)); } module.exports = { checkTableStructure };