time-distribution api performance

This commit is contained in:
feie9454 2025-10-02 19:40:12 +08:00
parent 7b5b73fb1a
commit 5a97bc2a8d
3 changed files with 28 additions and 47 deletions

View File

@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
import { withCors } from '@/lib/middleware'
import { Prisma } from '@prisma/client' // 为了 Prisma.sql / Prisma.join
async function handleTimeDistribution(req: NextRequest) {
try {
@ -12,55 +13,35 @@ async function handleTimeDistribution(req: NextRequest) {
return NextResponse.json({ error: '缺少主机名' }, { status: 400 })
}
// Get all records for the hostname and group by hour
const records = await prisma.record.findMany({
where: { hostname },
select: {
timestamp: true
}
})
const sp = req.nextUrl.searchParams
const fromParam = sp.get('from') // ISO如 2025-09-01T00:00:00Z
const toParam = sp.get('to') // ISO
// Group by hour
interface DistributionEntry {
timestamp: number
count: number
}
const whereParts: any[] = [Prisma.sql`"hostname" = ${hostname}`]
if (fromParam) whereParts.push(Prisma.sql`"timestamp" >= ${new Date(fromParam)}`)
if (toParam) whereParts.push(Prisma.sql`"timestamp" < ${new Date(toParam)}`)
const distribution = records.reduce((acc: DistributionEntry[], record: { timestamp: Date }) => {
const timestamp = new Date(record.timestamp)
// Create hour-level timestamp (set minutes, seconds, ms to 0)
const hourTimestamp = new Date(
timestamp.getFullYear(),
timestamp.getMonth(),
timestamp.getDate(),
timestamp.getHours(),
0, 0, 0
const rows = await prisma.$queryRaw<
{ ts: bigint | number; count: number }[]
>(Prisma.sql`
SELECT
EXTRACT(EPOCH FROM date_trunc('hour', "timestamp"))::bigint AS ts,
COUNT(*)::int AS count
FROM "records"
WHERE ${Prisma.join(whereParts, ' AND ')}
GROUP BY 1
ORDER BY 1
`)
// JSON 不支持 BigInt转成 number秒级时间戳安全
const distribution = rows.map(r => ({
timestamp: Number(r.ts),
count: r.count
}))
return NextResponse.json(
{ hostname, distribution },
)
const existingEntry = acc.find(entry =>
entry.timestamp === Math.floor(hourTimestamp.getTime() / 1000)
)
if (existingEntry) {
existingEntry.count++
} else {
acc.push({
timestamp: Math.floor(hourTimestamp.getTime() / 1000),
count: 1
})
}
return acc
}, [])
// Sort by timestamp
distribution.sort((a: DistributionEntry, b: DistributionEntry) => a.timestamp - b.timestamp)
return NextResponse.json({
hostname,
distribution
})
} catch (error) {
console.error('获取时间分布统计失败:', error)
return NextResponse.json({ error: '获取时间分布统计失败' }, { status: 500 })

View File

View File