refactor: 移除运行时数据库初始化与分区维护
- 删除了服务启动阶段的数据库初始化逻辑,包括创建数据库、表和分区的相关代码。 - 移除了定时分区维护任务,确保服务职责更清晰。 - 更新了数据库分区策略,明确分区由外部脚本管理,服务不再自动创建缺失分区。 - 修改了相关文档,确保数据库结构与分区维护的责任转移到 `SQL_Script/` 目录下的外部脚本。 - 更新了需求和场景,确保符合新的设计规范。
This commit is contained in:
6
SQL_Script/create_database.sql
Normal file
6
SQL_Script/create_database.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
-- Replace {{DATABASE_NAME}} before execution
|
||||
-- Requires psql (uses \gexec)
|
||||
SELECT format('CREATE DATABASE %I', '{{DATABASE_NAME}}')
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM pg_database WHERE datname = '{{DATABASE_NAME}}'
|
||||
)\gexec;
|
||||
12
SQL_Script/create_partition_for_day.sql
Normal file
12
SQL_Script/create_partition_for_day.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- Replace placeholders before execution:
|
||||
-- {{SCHEMA_NAME}} default: onoffline
|
||||
-- {{TABLE_NAME}} default: onoffline_record
|
||||
-- {{PARTITION_SUFFIX}} format: YYYYMMDD (example: 20260304)
|
||||
-- {{START_TS_MS}} unix ms at 00:00:00.000
|
||||
-- {{END_TS_MS}} unix ms at next day 00:00:00.000
|
||||
-- {{TABLESPACE_CLAUSE}} either empty string or: TABLESPACE ts_hot
|
||||
|
||||
CREATE TABLE IF NOT EXISTS {{SCHEMA_NAME}}.{{TABLE_NAME}}_{{PARTITION_SUFFIX}}
|
||||
PARTITION OF {{SCHEMA_NAME}}.{{TABLE_NAME}}
|
||||
FOR VALUES FROM ({{START_TS_MS}}) TO ({{END_TS_MS}})
|
||||
{{TABLESPACE_CLAUSE}};
|
||||
27
SQL_Script/create_schema_and_parent_table.sql
Normal file
27
SQL_Script/create_schema_and_parent_table.sql
Normal file
@@ -0,0 +1,27 @@
|
||||
-- Replace placeholders before execution:
|
||||
-- {{SCHEMA_NAME}} default: onoffline
|
||||
-- {{TABLE_NAME}} default: onoffline_record
|
||||
|
||||
CREATE SCHEMA IF NOT EXISTS {{SCHEMA_NAME}};
|
||||
|
||||
CREATE TABLE IF NOT EXISTS {{SCHEMA_NAME}}.{{TABLE_NAME}} (
|
||||
guid TEXT NOT NULL,
|
||||
ts_ms BIGINT NOT NULL,
|
||||
write_ts_ms BIGINT NOT NULL,
|
||||
hotel_id SMALLINT,
|
||||
mac TEXT,
|
||||
device_id TEXT,
|
||||
room_id TEXT,
|
||||
ip TEXT,
|
||||
current_status TEXT,
|
||||
launcher_version TEXT,
|
||||
reboot_reason TEXT,
|
||||
PRIMARY KEY (ts_ms, guid)
|
||||
) PARTITION BY RANGE (ts_ms);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_{{TABLE_NAME}}_guid ON {{SCHEMA_NAME}}.{{TABLE_NAME}} (guid);
|
||||
CREATE INDEX IF NOT EXISTS idx_{{TABLE_NAME}}_device_id ON {{SCHEMA_NAME}}.{{TABLE_NAME}} (device_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_{{TABLE_NAME}}_hotel_id ON {{SCHEMA_NAME}}.{{TABLE_NAME}} (hotel_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_{{TABLE_NAME}}_mac ON {{SCHEMA_NAME}}.{{TABLE_NAME}} (mac);
|
||||
CREATE INDEX IF NOT EXISTS idx_{{TABLE_NAME}}_room_id ON {{SCHEMA_NAME}}.{{TABLE_NAME}} (room_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_{{TABLE_NAME}}_status ON {{SCHEMA_NAME}}.{{TABLE_NAME}} (current_status);
|
||||
26
SQL_Script/generate_init_sql.js
Normal file
26
SQL_Script/generate_init_sql.js
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const args = Object.fromEntries(
|
||||
process.argv.slice(2).map((arg) => {
|
||||
const [key, value] = arg.split('=');
|
||||
return [key.replace(/^--/, ''), value];
|
||||
})
|
||||
);
|
||||
|
||||
const database = args.database || 'log_platform';
|
||||
const schema = args.schema || 'onoffline';
|
||||
const table = args.table || 'onoffline_record';
|
||||
const output = args.output;
|
||||
|
||||
const sql = `SELECT format('CREATE DATABASE %I', '${database}')\nWHERE NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = '${database}')\\gexec;\n\nCREATE SCHEMA IF NOT EXISTS ${schema};\n\nCREATE TABLE IF NOT EXISTS ${schema}.${table} (\n guid TEXT NOT NULL,\n ts_ms BIGINT NOT NULL,\n write_ts_ms BIGINT NOT NULL,\n hotel_id SMALLINT,\n mac TEXT,\n device_id TEXT,\n room_id TEXT,\n ip TEXT,\n current_status TEXT,\n launcher_version TEXT,\n reboot_reason TEXT,\n PRIMARY KEY (ts_ms, guid)\n) PARTITION BY RANGE (ts_ms);\n\nCREATE INDEX IF NOT EXISTS idx_${table}_guid ON ${schema}.${table} (guid);\nCREATE INDEX IF NOT EXISTS idx_${table}_device_id ON ${schema}.${table} (device_id);\nCREATE INDEX IF NOT EXISTS idx_${table}_hotel_id ON ${schema}.${table} (hotel_id);\nCREATE INDEX IF NOT EXISTS idx_${table}_mac ON ${schema}.${table} (mac);\nCREATE INDEX IF NOT EXISTS idx_${table}_room_id ON ${schema}.${table} (room_id);\nCREATE INDEX IF NOT EXISTS idx_${table}_status ON ${schema}.${table} (current_status);\n`;
|
||||
|
||||
if (output) {
|
||||
const outputPath = path.resolve(output);
|
||||
fs.writeFileSync(outputPath, sql, 'utf8');
|
||||
console.log(`Init SQL written to ${outputPath}`);
|
||||
} else {
|
||||
process.stdout.write(sql);
|
||||
}
|
||||
64
SQL_Script/generate_partition_range_sql.js
Normal file
64
SQL_Script/generate_partition_range_sql.js
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const args = Object.fromEntries(
|
||||
process.argv.slice(2).map((arg) => {
|
||||
const [key, value] = arg.split('=');
|
||||
return [key.replace(/^--/, ''), value];
|
||||
})
|
||||
);
|
||||
|
||||
const schema = args.schema || 'onoffline';
|
||||
const table = args.table || 'onoffline_record';
|
||||
const start = args.start;
|
||||
const days = Number(args.days || '30');
|
||||
const tablespace = args.tablespace || '';
|
||||
const output = args.output;
|
||||
|
||||
if (!start) {
|
||||
console.error('Missing required argument: --start=YYYY-MM-DD');
|
||||
process.exit(1);
|
||||
}
|
||||
if (!Number.isFinite(days) || days <= 0) {
|
||||
console.error('Invalid --days value. It must be a positive integer.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const base = new Date(`${start}T00:00:00`);
|
||||
if (Number.isNaN(base.getTime())) {
|
||||
console.error('Invalid start date. Use format YYYY-MM-DD');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const statements = [];
|
||||
for (let i = 0; i < days; i += 1) {
|
||||
const date = new Date(base);
|
||||
date.setDate(base.getDate() + i);
|
||||
|
||||
const startMs = date.getTime();
|
||||
const endDate = new Date(date);
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
const endMs = endDate.getTime();
|
||||
|
||||
const yyyy = date.getFullYear();
|
||||
const mm = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const dd = String(date.getDate()).padStart(2, '0');
|
||||
const suffix = `${yyyy}${mm}${dd}`;
|
||||
|
||||
const tablespaceClause = tablespace ? ` TABLESPACE ${tablespace}` : '';
|
||||
statements.push(
|
||||
`CREATE TABLE IF NOT EXISTS ${schema}.${table}_${suffix}\nPARTITION OF ${schema}.${table}\nFOR VALUES FROM (${startMs}) TO (${endMs})${tablespaceClause};`
|
||||
);
|
||||
}
|
||||
|
||||
const sql = `${statements.join('\n\n')}\n`;
|
||||
|
||||
if (output) {
|
||||
const outputPath = path.resolve(output);
|
||||
fs.writeFileSync(outputPath, sql, 'utf8');
|
||||
console.log(`Partition range SQL written to ${outputPath}`);
|
||||
} else {
|
||||
process.stdout.write(sql);
|
||||
}
|
||||
49
SQL_Script/generate_partition_sql.js
Normal file
49
SQL_Script/generate_partition_sql.js
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const args = Object.fromEntries(
|
||||
process.argv.slice(2).map((arg) => {
|
||||
const [key, value] = arg.split('=');
|
||||
return [key.replace(/^--/, ''), value];
|
||||
})
|
||||
);
|
||||
|
||||
const schema = args.schema || 'onoffline';
|
||||
const table = args.table || 'onoffline_record';
|
||||
const dateInput = args.date;
|
||||
const tablespace = args.tablespace || '';
|
||||
const output = args.output;
|
||||
|
||||
if (!dateInput) {
|
||||
console.error('Missing required argument: --date=YYYY-MM-DD');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const date = new Date(`${dateInput}T00:00:00`);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
console.error('Invalid date. Use format YYYY-MM-DD');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const startMs = date.getTime();
|
||||
const endDate = new Date(date);
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
const endMs = endDate.getTime();
|
||||
|
||||
const yyyy = date.getFullYear();
|
||||
const mm = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const dd = String(date.getDate()).padStart(2, '0');
|
||||
const suffix = `${yyyy}${mm}${dd}`;
|
||||
const tablespaceClause = tablespace ? `TABLESPACE ${tablespace}` : '';
|
||||
|
||||
const sql = `CREATE TABLE IF NOT EXISTS ${schema}.${table}_${suffix}\nPARTITION OF ${schema}.${table}\nFOR VALUES FROM (${startMs}) TO (${endMs})\n${tablespaceClause};\n`;
|
||||
|
||||
if (output) {
|
||||
const outputPath = path.resolve(output);
|
||||
fs.writeFileSync(outputPath, sql, 'utf8');
|
||||
console.log(`Partition SQL written to ${outputPath}`);
|
||||
} else {
|
||||
process.stdout.write(sql);
|
||||
}
|
||||
Reference in New Issue
Block a user