如何在Flask中定时更新视图函数所用变量以避免重复查询大表
更优的推荐方案
首选PostgreSQL内置物化视图+定时刷新的方案,实现成本和性能都优于你列出的三个选项:
- 直接在数据库层创建物化视图存储每个imei对应的最新日期:
CREATE MATERIALIZED VIEW gps_latest_date AS SELECT imei, max(timestamp_utc::date) AS latest_date FROM gps_data GROUP BY imei; -- 给imei加唯一索引,查询速度拉满 CREATE UNIQUE INDEX idx_mv_imei ON gps_latest_date(imei);
- 每天定时执行一句
REFRESH MATERIALIZED VIEW gps_latest_date;即可,刷新性能远高于应用层拉取数据计算,也不需要额外引入中间件。 - 原路由的查询直接改成查这个物化视图,单条索引查询耗时基本在1ms以内,完全不会有性能问题。
如果你的最新日期需要更高的实时性,还可以改用专用小表+触发器更新的方案:建一个只有imei和latest_date两个字段的小表,每次gps_data写入新数据的时候,用数据库触发器自动更新对应imei的latest_date值,不需要任何定时任务,数据永远是最新的,查询性能和物化视图方案一致。
现有三个方案的优劣对比
优先级从高到低排序为:方案3 > 方案1 > 方案2
- 方案3(加联合索引):如果不想改动现有逻辑,直接给
(imei, timestamp_utc DESC)建联合索引,PostgreSQL的max查询会直接走索引取第一条,不需要扫全表,性能已经足够支撑普通访问量的场景,唯一缺点是每次请求还是要查一次数据库,不过单次查询开销极低。 - 方案1(Celery+Redis):适合访问量极大、完全不想透穿到数据库的场景,缺点是需要额外维护Celery和Redis两个组件,运维成本上升,还要处理缓存失效、冷启动缓存为空的兜底逻辑。
- 方案2(全局变量+后台线程):不推荐,首先Flask如果用多进程部署(比如uWSGI、Gunicorn开多worker),每个进程的全局变量是独立的,需要每个进程都跑一个后台线程更新,重复计算浪费资源,而且进程重启的时候会出现数据为空的情况,稳定性很差。
内容的提问来源于stack exchange,提问作者Eduardo G
相关产品推荐
相关产品推荐

