运营要"昨晚八点到十点的在线人数曲线",学员的服务器只维护一个当前在线数——每分钟被覆盖一次,历史无迹可查,曲线永远画不出来。也有学员把每次变化都存一条记录,在线人数频繁波动一天产生数万条记录,查询一周的数据要扫全表。时序数据的正确姿势是定频留痕:固定周期存一个点,按周期定位查询。错误场景:
local onlineNow = 0
local function onPlayerEnter()
onlineNow = onlineNow + 1
end
只有当前值,没有历史序列,运营要曲线时无能为力。
每分钟落一个点:以分钟号为下标存进数组,查询时按起止分钟号直接定位区间,需要历史时周期归档。规范写法。示例代码如下:
local series = {}
local lastMinute = -1
local function tickOnline(count)
local minute = math.floor(os.time() / 60)
if minute ~= lastMinute then
lastMinute = minute
series[#series + 1] = { m = minute, n = count }
end
end
local function queryRange(fromTs, toTs)
local fromM = math.floor(fromTs / 60)
local toM = math.floor(toTs / 60)
local out = {}
for _, p in ipairs(series) do
if p.m >= fromM and p.m <= toM then
out[#out + 1] = p
end
end
return out
end
每分钟最多追加一条,一天 1440 个点;queryRange 用分钟号区间过滤,一周的曲线一次线性扫描取完。示例代码如下:
local pts = queryRange(os.time() - 86400, os.time())
for _, p in ipairs(pts) do
print(os.date("%H:%M", p.m * 60) .. " " .. p.n .. " 人在线")
end
三步验证:模拟 3 分钟内多次人数变化,序列里只有 3 个点且每分钟一个;查询起止区间外的点不被返回;存满一天 1440 点后查询单日曲线的耗时在 1 毫秒内。
存储周期越长越省但曲线越粗:降采样按 15 分钟聚合一个点(取区间均值),一个月的数据从 43200 点缩到 2880 点,月度报表够用。示例代码如下:
local function downsample(series, groupMin)
local out = {}
for i = 1, #series, groupMin do
local sum, cnt = 0, 0
for j = i, math.min(i + groupMin - 1, #series) do
sum = sum + series[j].n
cnt = cnt + 1
end
out[#out + 1] = { m = series[i].m, n = sum / cnt }
end
return out
end
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
一、抛坑提问:500 件掉落物要按名字即时改爆率,每次线性扫 500 项还是建一次索引?反向索引把"名字到位置"变成 O(1…
一、一行代码拆解:MIGRATE[1] = function(c) ... end —— 这一行把版本升级写成补丁链:从旧版…
一、隐蔽陷阱:给装备对象做播报,"装备" .. obj 报 attempt to concatenate a table v…
一、线上事故:守城加成函数 5 个参数,12 处调用每处传全量,一次改签名漏改 4 处,加成系数错发 2 小时。 二、底层原…
一、线上事故:掉落码含竖线与引号直接进聊天广播,被消息管道当分隔符切碎,500 条掉落码 88 条残缺,捡包脚本集体失灵。 …
一、抛坑提问:公告模板 "({name}({count}))" 括号层层嵌套,怎么在渲染前就知道它不会烂?栈式配对扫一遍字符…