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 }; |