128 lines
4.0 KiB
JavaScript
128 lines
4.0 KiB
JavaScript
|
|
/**
|
|||
|
|
* 检查数据库中所有表的主键ID分布情况
|
|||
|
|
* @file check-primary-keys.js
|
|||
|
|
* @description 分析各表的主键ID范围,为重新排序做准备
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const { sequelize } = require('./config/database-simple');
|
|||
|
|
const { QueryTypes } = require('sequelize');
|
|||
|
|
|
|||
|
|
async function checkPrimaryKeys() {
|
|||
|
|
try {
|
|||
|
|
console.log('=== 检查数据库表主键ID分布情况 ===\n');
|
|||
|
|
|
|||
|
|
// 获取所有表名
|
|||
|
|
const tables = await sequelize.query(
|
|||
|
|
"SELECT TABLE_NAME as table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'",
|
|||
|
|
{ type: QueryTypes.SELECT }
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
console.log(`发现 ${tables.length} 个表:\n`);
|
|||
|
|
|
|||
|
|
const tableStats = [];
|
|||
|
|
|
|||
|
|
for (const table of tables) {
|
|||
|
|
const tableName = table.table_name;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 检查表是否有id字段
|
|||
|
|
const columns = await sequelize.query(
|
|||
|
|
`SELECT COLUMN_NAME as column_name, DATA_TYPE as data_type, IS_NULLABLE as is_nullable, COLUMN_KEY as column_key
|
|||
|
|
FROM information_schema.columns
|
|||
|
|
WHERE table_schema = DATABASE() AND TABLE_NAME = '${tableName}' AND COLUMN_NAME = 'id'`,
|
|||
|
|
{ type: QueryTypes.SELECT }
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if (columns.length === 0) {
|
|||
|
|
console.log(`❌ ${tableName}: 没有id字段`);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取ID统计信息
|
|||
|
|
const stats = await sequelize.query(
|
|||
|
|
`SELECT
|
|||
|
|
COUNT(*) as total_count,
|
|||
|
|
MIN(id) as min_id,
|
|||
|
|
MAX(id) as max_id,
|
|||
|
|
COUNT(DISTINCT id) as unique_count
|
|||
|
|
FROM ${tableName}`,
|
|||
|
|
{ type: QueryTypes.SELECT }
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
const stat = stats[0];
|
|||
|
|
|
|||
|
|
// 检查ID连续性
|
|||
|
|
const gapCheck = await sequelize.query(
|
|||
|
|
`SELECT COUNT(*) as gap_count
|
|||
|
|
FROM (
|
|||
|
|
SELECT id + 1 as next_id
|
|||
|
|
FROM ${tableName}
|
|||
|
|
WHERE id + 1 NOT IN (SELECT id FROM ${tableName})
|
|||
|
|
AND id < (SELECT MAX(id) FROM ${tableName})
|
|||
|
|
) as gaps`,
|
|||
|
|
{ type: QueryTypes.SELECT }
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
const hasGaps = gapCheck[0].gap_count > 0;
|
|||
|
|
|
|||
|
|
const tableInfo = {
|
|||
|
|
tableName,
|
|||
|
|
totalCount: parseInt(stat.total_count),
|
|||
|
|
minId: stat.min_id,
|
|||
|
|
maxId: stat.max_id,
|
|||
|
|
uniqueCount: parseInt(stat.unique_count),
|
|||
|
|
hasGaps,
|
|||
|
|
needsReorder: stat.min_id !== 1 || hasGaps
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
tableStats.push(tableInfo);
|
|||
|
|
|
|||
|
|
console.log(`✅ ${tableName}:`);
|
|||
|
|
console.log(` - 记录数: ${tableInfo.totalCount}`);
|
|||
|
|
console.log(` - ID范围: ${tableInfo.minId} - ${tableInfo.maxId}`);
|
|||
|
|
console.log(` - 唯一ID数: ${tableInfo.uniqueCount}`);
|
|||
|
|
console.log(` - 有间隙: ${hasGaps ? '是' : '否'}`);
|
|||
|
|
console.log(` - 需要重排: ${tableInfo.needsReorder ? '是' : '否'}`);
|
|||
|
|
console.log('');
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.log(`❌ ${tableName}: 检查失败 - ${error.message}`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 汇总统计
|
|||
|
|
console.log('\n=== 汇总统计 ===');
|
|||
|
|
const needReorderTables = tableStats.filter(t => t.needsReorder);
|
|||
|
|
console.log(`需要重新排序的表: ${needReorderTables.length}/${tableStats.length}`);
|
|||
|
|
|
|||
|
|
if (needReorderTables.length > 0) {
|
|||
|
|
console.log('\n需要重新排序的表:');
|
|||
|
|
needReorderTables.forEach(table => {
|
|||
|
|
console.log(`- ${table.tableName} (${table.minId}-${table.maxId}, ${table.totalCount}条记录)`);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return tableStats;
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('检查主键失败:', error);
|
|||
|
|
throw error;
|
|||
|
|
} finally {
|
|||
|
|
await sequelize.close();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果直接运行此脚本
|
|||
|
|
if (require.main === module) {
|
|||
|
|
checkPrimaryKeys()
|
|||
|
|
.then(() => {
|
|||
|
|
console.log('\n检查完成!');
|
|||
|
|
process.exit(0);
|
|||
|
|
})
|
|||
|
|
.catch(error => {
|
|||
|
|
console.error('检查失败:', error);
|
|||
|
|
process.exit(1);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = { checkPrimaryKeys };
|