为什么PostgreSQL不自动缓存执行计划?这可能是最硬核的优化解读
为什么PostgreSQL不自动缓存执行计划?这可能是最硬核的优化解读
前言
在数据库性能方面,查询语句的执行计划是最关键的因素之一。每当数据库接收到一个查询时,它必须决定如何以最有效的方式执行该查询。这个决策过程——称为执行计划。 计算并生成最优的执行计划在时间上可能非常昂贵,尤其是对于经常执行的查询语句。为了减轻这种开销,数据库采用执行计划缓存(Oracle和SQL Server都会自动缓存执行计划)来解决这个问题,使它们能够重用先前计算的执行策略,而不是每次执行时都重新计算执行计划。
然而,执行计划缓存的工作方式在不同的数据库系统之间可能存在显著差异。PostgreSQL 对执行计划缓存采用了一种更加动态和自适应的方法,而 SQL Server 默认则会积极缓存所有语句的执行计划,从而导致性能上的巨大差异。
这里会深入探讨 PostgreSQL 如何处理执行计划缓存,并将它与 SQL Server 进行比较,以及如何在针对这两个数据库进行性能优化。然后还将讨论预处理语句、函数缓存、通用与自定义执行计划,以及两个数据库中的常见性能陷阱。
PostgreSQL 如何缓存执行计划
PostgreSQL 并不会自动缓存SQL 语句的执行计划。每次执行SQL 查询(如 SELECT、INSERT、UPDATE 或 DELETE)时,PostgreSQL 都会从头开始解析、优化生成执行计划并执行该查询。
这一行为与 SQL Server 大相径庭,但是后者默认会全局缓存执行计划。虽然这看起来一开始是一个劣势,但实际上,这使得 PostgreSQL 在数据分布随时间变化的动态环境中能够做出更好的执行计划优化决策。然而,PostgreSQL 确实会在某些情况下缓存执行计划,包括prepare预处理语句和 PL/pgSQL 函数。
预处理语句和查询计划缓存
在 PostgreSQL 中如果要使用执行计划缓存,可以使用预处理语句。预处理语句允许 PostgreSQL 缓存查询的执行计划,这样每次执行查询时就不需要重新编译它。
PREPARE get_users (INT) AS
SELECT * FROM users WHERE age > $1;
EXECUTE get_users(30);
在上面例子中:
- 第一次调用 PREPARE 语句时,PostgreSQL 解析并规划查询。
- 当 EXECUTE 执行时,会重用缓存的执行计划,从而避免了额外的解析和规划开销。
自定义执行计划 vs. 通用执行计划
默认情况下,PostgreSQL 从自定义执行计划开始——该执行计划针对特定的参数值进行了优化。然而,如果一个prepare预处理语句被多次执行(通常是5次或更多次),PostgreSQL 会评估是否应该切换到通用执行计划。自定义执行计划是根据实际的参数值进行优化的,并且可能使用索引扫描、顺序扫描或其他优化的执行路径,这取决于数据的分布情况。
另一方面,通用执行计划是没有特定参数值的,而是依赖于来自 pg_statistic 的表统计信息来估算行的基数/选择性。这种方法消除了每次执行时的执行计划生成开销,但如果数据分布不均匀(数据倾斜),可能会导致查询使用的执行计划不佳。
PL/pgSQL 函数和执行计划缓存
PostgreSQL 还会在 PL/pgSQL 函数中缓存执行计划。当函数包含SQL语句时,PostgreSQL 在第一次执行后会缓存执行计划。
CREATE FUNCTION get_users_by_age(age_limit INT)
RETURNS SETOF users AS $$
BEGIN
RETURN QUERY SELECT * FROM users WHERE age > age_limit;
END;
$$ LANGUAGE plpgsql;
第一次运行该函数时,PostgreSQL 会为 SELECT 语句创建一个缓存的执行计划。如果该函数被频繁调用,PostgreSQL 可能会像处理预处理语句一样切换到通用执行计划。为了控制这一行为,PostgreSQL 允许开发人员手动强制指定缓存策略:
ALTER FUNCTION get_users_by_age SET plan_cache_mode = 'force_custom_plan';
ALTER FUNCTION get_users_by_age SET plan_cache_mode = 'force_generic_plan';
理解索引下的执行计划行为
PostgreSQL 决定使用自定义执行计划还是通用执行计划的一个主要因素是索引选择性。如果某个字段具有高基数(有很多唯一值),通常使用索引扫描是最佳选择。然而,如果某个字段具有低基数(唯一值较少),顺序扫描可能更高效。例如,考虑以下情况:
CREATE INDEX idx_users_age ON users(age);
如果大多数年龄值分布均匀,PostgreSQL 可能更倾向于使用通用执行计划,因为参数变化对执行时间的影响不大。然而,如果某些值出现频率较高(例如:年龄 = 25 占据了表 60% 的行数),使用自定义执行计划将更有效。
总结
理解执行计划缓存的工作原理对于数据库性能调优至关重要。PostgreSQL 采取动态方法,避免了参数嗅探的陷阱,但需要明确配置以实现执行计划的重用。另一方面,SQL Server 激进地缓存执行计划,这可以减少每次执行计划生成的开销,但当参数值变化较大时,可能会引发参数嗅探问题。
对于从 SQL Server 转向 PostgreSQL 的开发人员,适应 PostgreSQL 的执行计划缓存行为可能需要一些时间。然而,通过谨慎使用prepare预处理语句、函数和 plan_cache_mode参数设置,开发人员可以精细调优 PostgreSQL,以实现最佳性能。

本文版权归作者所有,未经作者同意不得转载。
为什么PostgreSQL不自动缓存执行计划?这可能是最硬核的优化解读的更多相关文章
- SQL Server 执行计划缓存
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/内存池/缓冲区 概述 了解执行计划对数据库性能分析很重要,其中涉及到了语句性能分析与存储,这也是写这篇文章的目的,在了解执行计划之 ...
- 谈一谈SQL Server中的执行计划缓存(下)
简介 在上篇文章中我们谈到了查询优化器和执行计划缓存的关系,以及其二者之间的冲突.本篇文章中,我们会主要阐述执行计划缓存常见的问题以及一些解决办法. 将执行缓存考虑在内时的流程 上篇文章中提到了查询优 ...
- 谈一谈SQL Server中的执行计划缓存(上)
简介 我们平时所写的SQL语句本质只是获取数据的逻辑,而不是获取数据的物理路径.当我们写的SQL语句传到SQL Server的时候,查询分析器会将语句依次进行解析(Parse).绑定(Bind).查询 ...
- Sql Server中执行计划的缓存机制
Sql查询过程 当执行一个Sql语句或者存储过程时, Sql Server的大致过程是 1. 对查询语句进行分析,将其生成逻辑单元,并进行基本的语法检查 2. 生成查询树(会将查询语句中所有操作转换为 ...
- 浅析SQL Server中的执行计划缓存(上)
简介 我们平时所写的SQL语句本质只是获取数据的逻辑,而不是获取数据的物理路径.当我们写的SQL语句传到SQL Server的时候,查询分析器会将语句依次进行解析(Parse).绑定(Bind).查询 ...
- Execution Plan 执行计划介绍
后面的练习中需要下载 Demo 数据库, 有很多不同的版本, 可以根据个人需要下载. 下载地址 -http://msftdbprodsamples.codeplex.com/ 1. 什么是执行计划 ...
- mysql之优化器、执行计划、简单优化
mysql之优化器.执行计划.简单优化 2018-12-12 15:11 烟雨楼人 阅读(794) 评论(0) 编辑 收藏 引用连接: https://blog.csdn.net/DrDanger/a ...
- 查看ORACLE的实际执行计划
ORACLE的执行计划分为预估执行计划和实际执行计划.其中,你用Toad.PL/SQL Developer.SQL Developer.EXPLAIN PLAN FOR或者SET ATUOTRACE ...
- SQL 执行计划(一)
缓存执行计划 SQL Server 2008提供了一些服务器对象来分析执行计划Sys.dm_exec_cached_plans: 包含缓存的执行计划,每个执行计划对应一行.Sys.dm_exe ...
- SQL Sever 2008性能分析之执行计划
一直想找一些关于SQL语句性能调试的权威参考,但是有参考未必就能够做好调试 2的工作.我深信实践中得到的经验是最珍贵的,书本知识只是一个引导.本篇来源于<Inside Microsoft SQL ...
随机推荐
- 二叉树 (王道数据结构 C语言版)
2004.11.04 计算一颗给定二叉树的所有双分支节点个数 编写把一个树的所有左右子树进行交换的函数 求先序遍历中第k个结点的值 (1 <= k <= 二叉树中的结点个数) #inclu ...
- SMU Autumn 2024 Trial 1
A. Load Balancing 很明显题意要的就是让我们把每个数往平均值靠,这样就保证最大值-最小值最小 但是当sum%n !=0的时候就说明无法每个数都等于sum/n,所以处理的方法就是,先计算 ...
- 目前国内可用Docker镜像源汇总(截至2024年11月)
本文主要讲述了由于特殊原因国内的 Docker 镜像源出现问题,国内许多常见的镜像源如网易.百度等已不可用.文中介绍了中科大镜像源的暂时关闭情况,以及阿里镜像源包括私人阿里镜像加速器的使用方式,并提供 ...
- Mybatis搭建环境时需要注意事项
- Java 中的 young GC、old GC、full GC 和 mixed GC 的区别是什么?
Java 中的 young GC.old GC.full GC 和 mixed GC 的区别 在 Java 中,垃圾回收(GC)可以分为几种不同类型,包括 young GC.old GC.full G ...
- 小程序组件使用全局样式app.wxss
Component({ options: { addGlobalClass: true } })
- 又来一个挑战 Elastic 的,初识 SigLens
Elastic Stack 在日志领域具备无与伦比的地位,各类新兴的开源项目都声称比 Elastic 更节省资源,同时检索速度也不慢,比如 ClickHouse.Loki.OpenObserve.VM ...
- php 常用bc函数
bcadd - 加法,2个任意精度数字的加法计算bcsub - 减法bcmul - 乘法bcdiv - 除法bcpow - 乘方bcmod - 取模bcsqrt - 求二次方根bccomp - 比较两 ...
- 60个 Linux C/C++ 实战小项目,挑战年薪30万+
大家好啊!我是小康. 最近公众号后台收到好多小伙伴的私信: "小康哥,我已经把<C++ Primer>啃完了,Linux 环境也玩得差不多了,但就是不知道该做啥项目练手...&q ...
- Sentinel——热点规则
目录 热点规则 配置热点规则 API配置热点规则 热点规则 热点规则是用于实现热点参数限流的规则.热点参数限流指的是,在流控规则中指定对某方法参数的 QPS 限流后,当所有对该资源的请求URL中携带有 ...