fix(backend): уменьшить лишние записи SQLite
Docker images / prepare-release (push) Successful in 10s
Docker images / backend-image (push) Successful in 2m8s
Docker images / frontend-image (push) Successful in 3m14s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 47s
Docker images / publish-release (push) Successful in 12s

Убрать WAL TRUNCATE с hot path NetFlow, не писать неизменённые UPDATE
и служебные INSERT, кэшировать карты topology/analytics.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-09-07 20:22:20 +07:00
co-authored by Cursor
parent 5188b2aff2
commit 0e5fb065e2
20 changed files with 521 additions and 127 deletions
+68 -1
View File
@@ -8,18 +8,85 @@ import { env } from "../config.js"
import * as schema from "./schema.js"
export const SQLITE_BUSY_TIMEOUT_MS = 5000
/** ~16 MiB page cache (negative = KiB). */
export const SQLITE_CACHE_SIZE_KIB = 16_000
export const SQLITE_WAL_AUTOCHECKPOINT_PAGES = 1000
export interface SqliteWriteStats {
insert: number
update: number
delete: number
walCheckpoint: number
}
let writeTrace: SqliteWriteStats | null = null
function classifyWriteSql(sql: string): keyof Omit<SqliteWriteStats, "walCheckpoint"> | null {
const head = sql.trimStart().slice(0, 12).toUpperCase()
if (head.startsWith("INSERT")) return "insert"
if (head.startsWith("UPDATE")) return "update"
if (head.startsWith("DELETE")) return "delete"
return null
}
function installSqliteWriteTrace(handle: SqliteHandle): SqliteHandle {
const origPrepare = handle.prepare.bind(handle)
handle.prepare = ((sql: string) => {
const stmt = origPrepare(sql)
const kind = classifyWriteSql(sql)
if (!kind) return stmt
const origRun = stmt.run.bind(stmt)
stmt.run = ((...args: unknown[]) => {
if (writeTrace) writeTrace[kind] += 1
return origRun(...args)
}) as typeof stmt.run
return stmt
}) as typeof handle.prepare
const origExec = handle.exec.bind(handle)
handle.exec = ((sql: string) => {
if (writeTrace) {
for (const part of sql.split(";")) {
const kind = classifyWriteSql(part)
if (kind) writeTrace[kind] += 1
}
}
return origExec(sql)
}) as typeof handle.exec
const origPragma = handle.pragma.bind(handle)
handle.pragma = ((source: string, options?: { simple?: boolean }) => {
if (writeTrace && /wal_checkpoint/i.test(source)) writeTrace.walCheckpoint += 1
return origPragma(source, options as never)
}) as typeof handle.pragma
return handle
}
export function countSqliteWrites<T>(fn: () => T): { result: T; stats: SqliteWriteStats } {
const stats: SqliteWriteStats = { insert: 0, update: 0, delete: 0, walCheckpoint: 0 }
writeTrace = stats
try {
return { result: fn(), stats }
} finally {
writeTrace = null
}
}
export function applySqlitePragmas(handle: SqliteHandle): void {
handle.pragma("journal_mode = WAL")
handle.pragma("foreign_keys = ON")
handle.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`)
handle.pragma("synchronous = NORMAL")
handle.pragma(`wal_autocheckpoint = ${SQLITE_WAL_AUTOCHECKPOINT_PAGES}`)
handle.pragma("temp_store = MEMORY")
handle.pragma(`cache_size = -${SQLITE_CACHE_SIZE_KIB}`)
}
function openSqlite(): SqliteHandle {
const handle = new Database(env.DATABASE_PATH)
applySqlitePragmas(handle)
return handle
return installSqliteWriteTrace(handle)
}
let sqlite = openSqlite()