手动收集统计信息面临的挑战
- 业务干扰:手动收集统计信息时,可能会对正在进行的频繁更新操作造成锁冲突,影响业务的实时性。因为收集统计信息可能需要短暂锁定表,导致更新操作等待。
- 及时性问题:频繁更新意味着数据变化快,手动收集时机难以把握。如果收集间隔过长,统计信息可能过时,影响查询优化;若间隔过短,又会增加系统负担和对业务的干扰。
- 准确性难题:由于数据更新频繁,在收集统计信息过程中数据可能又发生了变化,这就难以保证收集到的统计信息能准确反映当前数据状态。
手动收集统计信息方案思路
- 确定合适的收集时机:选择业务低峰期进行统计信息收集,比如凌晨等时间段,此时对业务实时性影响相对较小。
- 使用异步处理:采用异步任务机制,将统计信息收集任务放到后台执行,避免阻塞业务操作。例如使用pg_cron扩展来调度任务,在低峰期自动触发收集操作。
- 部分收集策略:对于大表或更新频繁的分区,可以采用部分收集统计信息的方式。只收集最近更新或变动较大的分区数据的统计信息,而不是全表收集,减少收集时间和对业务的影响。
技术细节
- pg_cron 配置:
- 安装 pg_cron 扩展:如果 PostgreSQL 未安装该扩展,需要按照官方文档进行安装。
- 创建定时任务:使用
CREATE EXTENSION pg_cron;
启用扩展后,通过 SELECT cron.schedule('0 2 * * *', 'ANALYZE your_table;');
这样的语句来设置在凌晨2点执行对 your_table
的统计信息收集任务。cron.schedule
第一个参数是 cron 表达式,用于定义任务执行时间;第二个参数是要执行的 SQL 命令。
- 部分收集:
- 对于分区表,可以通过指定分区名称来进行部分收集。例如,假设分区表
your_table
按日期分区,要收集最近一周的分区统计信息,可以使用 ANALYZE your_table_p20240101;
(假设 your_table_p20240101
是最近一周内的某个分区)。
- 可以结合系统视图(如
pg_catalog.pg_partitions
)来动态获取需要收集统计信息的分区,编写脚本实现自动化部分收集。例如,查询最近更新的分区并执行 ANALYZE
命令:
-- 获取最近更新的分区
SELECT partitionname
FROM pg_catalog.pg_partitions
WHERE tablename = 'your_table'
ORDER BY last_updated DESC
LIMIT 10;
-- 对获取到的分区执行ANALYZE
DO $$
DECLARE
partition_name text;
BEGIN
FOR partition_name IN
SELECT partitionname
FROM pg_catalog.pg_partitions
WHERE tablename = 'your_table'
ORDER BY last_updated DESC
LIMIT 10
LOOP
EXECUTE 'ANALYZE ' || partition_name || ';';
END LOOP;
END $$;
- 监控与调整:
- 建立监控机制,通过查看系统视图(如
pg_stat_activity
)监控收集统计信息任务对业务的影响。如果发现对业务有较大干扰,调整收集时间或策略。
- 定期评估统计信息的准确性,例如通过对比实际查询性能与查询优化器基于统计信息生成的执行计划预期性能,来判断是否需要进一步优化收集策略。