为什么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不自动缓存执行计划?这可能是最硬核的优化解读的更多相关文章

  1. SQL Server 执行计划缓存

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/内存池/缓冲区 概述 了解执行计划对数据库性能分析很重要,其中涉及到了语句性能分析与存储,这也是写这篇文章的目的,在了解执行计划之 ...

  2. 谈一谈SQL Server中的执行计划缓存(下)

    简介 在上篇文章中我们谈到了查询优化器和执行计划缓存的关系,以及其二者之间的冲突.本篇文章中,我们会主要阐述执行计划缓存常见的问题以及一些解决办法. 将执行缓存考虑在内时的流程 上篇文章中提到了查询优 ...

  3. 谈一谈SQL Server中的执行计划缓存(上)

    简介 我们平时所写的SQL语句本质只是获取数据的逻辑,而不是获取数据的物理路径.当我们写的SQL语句传到SQL Server的时候,查询分析器会将语句依次进行解析(Parse).绑定(Bind).查询 ...

  4. Sql Server中执行计划的缓存机制

    Sql查询过程 当执行一个Sql语句或者存储过程时, Sql Server的大致过程是 1. 对查询语句进行分析,将其生成逻辑单元,并进行基本的语法检查 2. 生成查询树(会将查询语句中所有操作转换为 ...

  5. 浅析SQL Server中的执行计划缓存(上)

    简介 我们平时所写的SQL语句本质只是获取数据的逻辑,而不是获取数据的物理路径.当我们写的SQL语句传到SQL Server的时候,查询分析器会将语句依次进行解析(Parse).绑定(Bind).查询 ...

  6. Execution Plan 执行计划介绍

    后面的练习中需要下载 Demo 数据库, 有很多不同的版本, 可以根据个人需要下载.  下载地址 -http://msftdbprodsamples.codeplex.com/ 1. 什么是执行计划 ...

  7. mysql之优化器、执行计划、简单优化

    mysql之优化器.执行计划.简单优化 2018-12-12 15:11 烟雨楼人 阅读(794) 评论(0) 编辑 收藏 引用连接: https://blog.csdn.net/DrDanger/a ...

  8. 查看ORACLE的实际执行计划

    ORACLE的执行计划分为预估执行计划和实际执行计划.其中,你用Toad.PL/SQL Developer.SQL Developer.EXPLAIN PLAN FOR或者SET ATUOTRACE ...

  9. SQL 执行计划(一)

    缓存执行计划  SQL Server 2008提供了一些服务器对象来分析执行计划Sys.dm_exec_cached_plans:    包含缓存的执行计划,每个执行计划对应一行.Sys.dm_exe ...

  10. SQL Sever 2008性能分析之执行计划

    一直想找一些关于SQL语句性能调试的权威参考,但是有参考未必就能够做好调试 2的工作.我深信实践中得到的经验是最珍贵的,书本知识只是一个引导.本篇来源于<Inside Microsoft SQL ...

随机推荐

  1. 文字像素(.NET)

    无图言* 代码实现 新建一个控制台应用程序, 调整 Program.cs 文件内容如下: using System; using System.Drawing; namespace ConsoleAp ...

  2. 古老的BAT文件在windows下的编辑

    直接上代码 rem echo choice /t 20 /d y /n >nul rem start/d "E:\service\exe" 8091.exe 8091 sta ...

  3. 安装yml 与 wget

    一.备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-B ...

  4. 一文搞懂Dockerfile

    Dockerfile官网 https://docs.docker.com/reference/dockerfile/ 什么是Dockerfile? Dockerfile 是一个文本文件,其内包含了一条 ...

  5. symfony4.4加密密码时报错Libsodium is not available. You should either install the sodium extension, upgrade

    报错: "Libsodium is not available. You should either install the sodium extension, upgrade to PHP ...

  6. 聊聊SpringAI流式输出的底层实现?

    在 Spring AI 中,流式输出(Streaming Output)是一种逐步返回 AI 模型生成结果的技术,允许服务器将响应内容分批次实时传输给客户端,而不是等待全部内容生成完毕后再一次性返回. ...

  7. 容器镜像基础(nydus)

    " 包括 nydus 的基本概念.架构和容器镜像加速使用方法. 1. nydus 1.1 存在的问题 对于容器镜像使用者 问题一:启动容器慢:容器启动慢的情况普遍发生在当用户启动一个很大的容 ...

  8. Asp.net core 少走弯路系列教程(二)HTML 学习

    前言 新人学习成本很高,网络上太多的名词和框架,全部学习会浪费大量的时间和精力. 新手缺乏学习内容的辨别能力,本系列文章为新手过滤掉不适合的学习内容(比如多线程等等),让新手少走弯路直通罗马. 作者认 ...

  9. IIS的垃圾回收对后台任务及隐形后台任务的影响

    IIS的垃圾回收引起的影响 错误排查 现象:在.net core api里创建的BackgroundService定义rabbitmq消费的逻辑,在一段时间运行后经常会出现消费任务中断,在日志里找了很 ...

  10. EFCore——树形结构篇

    1.整体数据量不大的场景 参照:EntityFramework Linq 查询数据获得树形结构-YES开发框架网 (yesdotnet.com) 核心方法GetChildData,特点将所有的数据查到 ...