大量设备查询¶
单元 14|难度:中级|前置:数据库、Redis、在线状态|目标:按列表、统计、导出和实时推送分别设计
先澄清“大量查询”是哪一种¶
不同需求不能使用同一个方案:
| 需求 | 合理方式 |
|---|---|
| 页面显示设备列表 | 数据库分页 + Redis 批量状态 |
| 查看当前在线总数 | 读取预计算统计或集合 cardinality |
| 导出全部设备 | 创建异步任务,游标/分批读取 |
| 分析历史遥测 | 时序聚合、降采样、异步报表 |
| 推送状态变化 | 事件 + WebSocket/SSE,而非不断全量刷新 |
页面列表¶
错误思路:
正确思路:
为什么在应用层合并并不一定浪费内存¶
应用层确实需要暂存数据库结果、Redis 结果和响应对象,但对象数量由页大小控制。真正危险的不是“应用层组装”,而是:
- 没有分页;
- 查询了不需要的字段;
- value 过大;
- 多份对象重复拷贝;
- 并发请求数量失控;
- 一次批量命令返回过多数据。
深分页¶
LIMIT 100 OFFSET 1000000 可能越来越慢,因为数据库仍需跳过大量记录。
更适合使用基于稳定排序键的游标分页:
SELECT id, name, model
FROM devices
WHERE tenant_id = :tenant_id
AND id > :last_id
ORDER BY id
LIMIT 100;
需要为过滤与排序模式设计合适索引。
在线总数¶
不要为了一个数字装载所有设备。可以:
SCARD tenant:{id}:online_devices;- 读取事件驱动维护的统计缓存;
- 对允许分钟级延迟的看板使用定时聚合;
- 定期校准,接受最终一致性。
全量导出¶
全量导出不是普通同步 HTTP 列表请求:
- 创建 export task;
- worker 按游标分批读取;
- 每批查询必要状态并写入文件流;
- 上传对象存储或保存临时文件;
- 通知用户下载;
- 设置文件过期和权限。
这既控制内存,也避免请求超时。
面试时诚实表达规模¶
我实际项目没有达到百万设备,但处理大量设备查询时会先区分列表、统计和全量任务。列表采用数据库游标分页,并对本页设备从 Redis 批量读取实时状态;统计读取预计算结果;全量导出则转为异步任务分批处理。这样不会把十万设备一次性加载到应用内存。
自测¶
- 列表、在线总数和全量导出为什么不能使用同一种查询?
- MGET 一次读取十万条为什么仍然危险?
- OFFSET 深分页为什么会越来越慢?
- 全量导出如何控制内存和请求超时?
完成标准¶
- 能为四类“大量查询”分别选方案
- 能解释应用层合并的内存边界
- 能写出游标分页条件
- 能设计异步导出流程
下一单元:设备影子与命令控制