一、什么是执行计划缓存
想象一下你去图书馆借书,每次都要重新查目录、找书架,效率肯定很低。数据库也一样,每次执行SQL语句时,如果都要重新规划查询路径(执行计划),性能就会受影响。openGauss的做法很聪明——把常用的执行计划存起来,下次直接用,这就是执行计划缓存。
举个例子:
-- 技术栈:openGauss
-- 第一次执行查询(需要生成执行计划)
EXPLAIN SELECT * FROM users WHERE age > 20;
-- 第二次执行相同查询时,直接复用缓存计划
SELECT * FROM users WHERE age > 20; -- 这次更快!
二、缓存机制如何工作
openGauss的缓存像个智能备忘录,它会:
- 识别SQL指纹:去掉多余空格、统一大小写,确保
SELECT * FROM users和select * from users被识别为同一个查询 - 缓存淘汰策略:当缓存满了,优先淘汰最近最少使用的计划(LRU算法)
- 参数控制:通过
plan_cache_mode参数可以设置强制使用/禁用缓存
看个实际参数配置示例:
-- 查看当前缓存模式
SHOW plan_cache_mode; -- 默认是'AUTO'(自动选择)
-- 强制使用缓存(适合稳定查询)
SET plan_cache_mode = 'FORCE';
三、什么情况下缓存会失效
缓存虽好,但遇到这些情况会被清空或重建:
- 表结构变更:比如给users表新增字段
- 统计信息更新:执行
ANALYZE users后 - 手动清理:执行
DISCARD PLANS命令
示例演示失效场景:
-- 先执行普通查询(生成缓存)
SELECT * FROM orders WHERE status = 'shipped';
-- 修改表结构导致缓存失效
ALTER TABLE orders ADD COLUMN discount NUMERIC;
-- 再次查询需要重新生成计划
SELECT * FROM orders WHERE status = 'shipped'; -- 这次变慢了
四、性能优化实战技巧
4.1 让更多查询命中缓存
- 写法标准化:团队统一SQL书写风格
- 绑定变量:用
?代替直接值,避免SELECT * FROM users WHERE id=1和id=2被当作不同查询
绑定变量示例:
-- 不推荐(无法复用缓存)
SELECT * FROM products WHERE category = 'electronics';
-- 推荐写法(使用绑定变量)
PREPARE prod_query (TEXT) AS
SELECT * FROM products WHERE category = $1;
EXECUTE prod_query('electronics');
4.2 监控缓存命中率
通过系统视图查看缓存效果:
-- 查看缓存统计(命中率越高越好)
SELECT * FROM pg_plan_cache_status;
-- 理想情况下命中率应超过85%
五、适用场景与注意事项
5.1 最适合的场景
- OLTP系统(短平快查询)
- 参数化查询多的应用
- 查询模式稳定的业务
5.2 需要小心的坑
- 复杂查询谨慎使用:20个表关联的查询,缓存可能反而降低性能
- 内存消耗:每个缓存计划约占用2-10KB内存
- 动态SQL问题:像
SELECT * FROM ${tableName}这种无法缓存
六、总结
执行计划缓存像是数据库的"肌肉记忆",合理利用能让查询速度提升30%以上。关键记住三点:
- 简单查询多用,复杂查询慎用
- 通过绑定变量提高命中率
- 定期监控
pg_plan_cache_status
最后给个优化检查清单:
-- 1. 检查当前缓存模式
SHOW plan_cache_mode;
-- 2. 分析缓存命中率
SELECT * FROM pg_plan_cache_status;
-- 3. 确认是否有无效缓存
SELECT * FROM pg_plan_cache_invalidations;
评论