深入探索PostgreSQL优化器的代价模型(建议收藏)

PawSQL优化引擎的实现深受PostgreSQL优化器的影响,本文我们来揭密PostgreSQL的代价模型。PawSQL专注于数据库性能优化自动化和智能化,提供的解决方案覆盖SQL开发、测试、运维的整个流程,广泛支持MySQL、PostgreSQL、OpenGauss、Oracle等主流商用和开源数据库,以及openGauss,人大金仓、达梦等国产数据库,为开发者和企业提供一站式的创新SQL优化解决方案,提升了数据库系统的稳定性、应用性能和基础设施利用率。

https://pawsql.com

图片

优化器的代价模型(Cost Model)是数据库查询优化器用于评估不同查询执行计划的代价,并选择最优执行计划的重要核心部分。PostgreSQL 的代价模型通过估算查询执行时的各种操作(如顺序扫描、索引扫描、连接等)的成本,来确定最有效率的查询执行路径。

📈代价的组成

PostgreSQL考虑了多个因素来估算成本:

  • CPU成本:处理元组的CPU时间

  • I/O成本:读取数据页的磁盘I/O时间

  • 网络成本:数据传输时间(对分布式查询)

📊 成本估算的公式

在 PostgreSQL 的源代码文件 src/backend/optimizer/path/costsize.c 中,每个成本估算函数都有特定的计算公式。下面我将对之前列出的所有成本函数逐一列出其计算公式,并解释各个公式中的主要变量。

以下是 PostgreSQL 中的成本估算函数的完整列表,包含每个函数的计算公式和变量解释,并按照类别进行组织:

1. 基础扫描操作的成本估算函数

1.1 cost_seqscan - 顺序扫描的成本估算

公式:

total_cost = startup_cost + run_cost
run_cost = seq_page_cost * pages + cpu_tuple_cost * tuples

变量解释:

  • startup_cost: 启动扫描的初始成本。

  • run_cost: 完成扫描所有数据的成本。

  • seq_page_cost: 顺序扫描每个页面的 I/O 成本。

  • pages: 需要读取的页面数。

  • cpu_tuple_cost: 处理每个元组的 CPU 成本。

  • tuples: 需要处理的元组数。


1.2 cost_index - 索引扫描的成本估算

公式:

total_cost = indexStartupCost + indexTotalCost + cpu_index_tuple_cost * tuples
indexTotalCost = random_page_cost * pages

变量解释:

  • indexStartupCost: 索引扫描的启动成本。

  • indexTotalCost: 索引扫描的总成本。

  • cpu_index_tuple_cost: 处理每个索引元组的 CPU 成本。

  • random_page_cost: 随机页面读取的 I/O 成本。

  • pages: 需要读取的页面数。

  • tuples: 需要处理的元组数。


1.3 cost_indexonlyscan - 索引仅扫描的成本估算

公式:

total_cost = indexStartupCost + indexTotalCost + cpu_index_tuple_cost * tuples

变量解释:

  • indexStartupCost: 索引扫描的启动成本。

  • indexTotalCost: 索引扫描的总成本。

  • cpu_index_tuple_cost: 处理每个索引元组的 CPU 成本。

  • tuples: 需要处理的元组数。


1.4 cost_bitmap_heap_scan - 位图堆扫描的成本估算

公式:

total_cost = startup_cost + run_cost
run_cost = page_cost + cpu_tuple_cost * tuples
page_cost = random_page_cost * pages

变量解释:

  • startup_cost: 启动扫描的初始成本。

  • run_cost: 完成扫描所有数据的成本。

  • random_page_cost: 随机页面读取的 I/O 成本。

  • page_cost: 需要读取页面的总 I/O 成本。

  • cpu_tuple_cost: 处理每个元组的 CPU 成本。

  • pages: 需要读取的页面数。

  • tuples: 需要处理的元组数。


1.5 cost_bitmap_tree_node - 位图索引扫描的成本估算

公式:

total_cost = cpu_cost + random_page_cost * pages

变量解释:

  • cpu_cost: 处理位图的 CPU 成本。

  • random_page_cost: 随机页面读取的 I/O 成本。

  • pages: 需要读取的页面数。


1.6 cost_subqueryscan - 子查询扫描的成本估算

公式:

total_cost = subquery_startup_cost + subquery_total_cost

变量解释:

  • subquery_startup_cost: 执行子查询的启动成本。

  • subquery_total_cost: 子查询的总执行成本。


1.7 cost_functionscan - 函数扫描的成本估算

公式:

total_cost = cpu_function_cost * num_function_calls

变量解释:

  • cpu_function_cost: 每次调用函数的 CPU 成本。

  • num_function_calls: 函数调用的次数。


1.8 cost_valuesscan - 值扫描的成本估算

公式:

total_cost = cpu_tuple_cost * num_tuples

变量解释:

  • cpu_tuple_cost: 处理每个元组的 CPU 成本。

  • num_tuples: 值扫描中的元组数。


1.9 cost_ctescan - 公用表表达式扫描的成本估算

公式:

total_cost = cte_startup_cost + cte_run_cost

变量解释:

  • cte_startup_cost: 执行 CTE 的启动成本。

  • cte_run_cost: 执行 CTE 的运行成本。


1.10 cost_tablefuncscan - 表函数扫描的成本估算

公式:

total_cost = cpu_function_cost * num_tuples

变量解释:

  • cpu_function_cost: 调用表函数时的 CPU 成本。

  • num_tuples: 表函数返回的元组数。


1.11 cost_tidscan - TID 扫描的成本估算

公式:

total_cost = random_page_cost * num_pages + cpu_tuple_cost * num_tuples

变量解释:

  • random_page_cost: 随机页面读取的 I/O 成本。

  • num_pages: 需要读取的页面数。

  • cpu_tuple_cost: 处理每个元组的 CPU 成本。

  • num_tuples: 需要处理的元组数。


1.12 cost_worktablescan - 工作表扫描的成本估算

公式:

total_cost = startup_cost + run_cost

变量解释:

  • startup_cost: 扫描的启动成本。

  • run_cost: 完成扫描的运行成本。


1.13 cost_foreignscan - 外部数据源扫描的成本估算

公式:

total_cost = foreign_scan_cost

变量解释:

  • foreign_scan_cost: 外部数据源提供的扫描成本。


2. 连接操作的成本估算函数

2.1 cost_nestloop - 嵌套循环连接的成本估算

公式:

total_cost = outer_cost + outer_tuples * inner_cost_per_tuple

变量解释:

  • outer_cost: 扫描外部表的总成本。

  • outer_tuples: 外部表中的元组数。

  • inner_cost_per_tuple: 内部表每个元组的扫描成本。


2.2 cost_mergejoin - 归并连接的成本估算

公式:

total_cost = outer_path_cost + inner_path_cost + merge_cost
merge_cost = cpu_operator_cost * num_outer * log2(num_inner)

变量解释:

  • outer_path_cost: 扫描外部表的成本。

  • inner_path_cost: 扫描内部表的成本。

  • merge_cost: 合并两个已排序输入的成本。

  • cpu_operator_cost: 每个连接操作的 CPU 成本。

  • num_outer: 外部表的行数。

  • num_inner: 内部表的行数。


2.3 cost_hashjoin - 哈希连接的成本估算

公式:

total_cost = outer_cost + inner_cost + hash_cost + probe_cost

变量解释:

  • outer_cost: 扫描外部表的成本。

  • inner_cost: 扫描内部表的成本。

  • hash_cost: 构建哈希表的成本。

  • probe_cost: 探测哈希表的成本。


3. 其他操作的成本估算函数

3.1 cost_sort - 排序操作的成本估算

公式:

total_cost = startup_cost + run_cost
run_cost = (log2(input_tuples) * input_tuples) * cpu_operator_cost

变量解释:

  • startup_cost: 启动排序的成本。

  • run_cost: 排序的运行成本。

  • input_tuples: 需要排序的元组数。

  • cpu_operator_cost: 每次比较操作的 CPU 成本。


3.2 cost_material - 物化操作的成本估算

公式:

total_cost = startup_cost + cpu_tuple_cost * tuples

变量解释:

  • startup_cost: 物化操作的启动成本。

  • cpu_tuple_cost: 处理每个元组的 CPU 成本。

  • tuples: 需要处理的元组数。


3.3 cost_agg - 聚合操作的成本估算

公式:

total_cost = cpu_agg_cost * numGroups

变量解释:

  • cpu_agg_cost: 每个聚合操作的 CPU 成本。

  • numGroups: 分组的数量。


3.4 cost_windowagg - 窗口聚合操作的成本估算

公式:

total_cost = cpu_windowagg_cost * numGroups

变量解释:

  • cpu_windowagg_cost: 每个窗口聚合操作的 CPU 成本。

  • numGroups: 窗口函数处理的分组数。


3.5 cost_group - 分组操作的成本估算

公式:

total_cost = cpu_group_cost * numGroups

变量解释:

  • cpu_group_cost: 每个分组操作的 CPU 成本。

  • numGroups: 分组的数量。


3.6 cost_unique - 唯一操作的成本估算

公式:

total_cost = cpu_unique_cost * numGroups

变量解释:

  • cpu_unique_cost: 去重操作的 CPU 成本。

  • numGroups: 处理的分组数量。


3.7 cost_setop - 集合操作的成本估算

公式:

total_cost = cpu_setop_cost * numGroups

变量解释:

  • cpu_setop_cost: 集合操作的 CPU 成本。

  • numGroups: 操作中涉及的分组数量。


3.8 cost_limit - LIMIT 操作的成本估算

公式:

total_cost = startup_cost + cpu_tuple_cost * limit_tuples

变量解释:

  • startup_cost: LIMIT 操作的启动成本。

  • cpu_tuple_cost: 处理每个元组的 CPU 成本。

  • limit_tuples: LIMIT 限制的元组数。


3.9 cost_result - Result 节点的成本估算

公式:

total_cost = cpu_result_cost

变量解释:

  • cpu_result_cost: 处理结果的 CPU 成本。


3.10 cost_append - Append 操作的成本估算

公式:

total_cost = startup_cost + run_cost

变量解释:

  • startup_cost: Append 操作的启动成本。

  • run_cost: 执行 Append 操作的运行成本。


3.11 cost_recursive_union - 递归 UNION 操作的成本估算

公式:

total_cost = left_cost + right_cost + recursive_cost

变量解释:

  • left_cost: 左子查询的成本。

  • right_cost: 右子查询的成本。

  • recursive_cost: 递归操作的成本。


4. 路径成本估算函数

4.1 get_path_cost - 获取路径成本

公式:

total_cost = path->total_cost

变量解释:

  • path->total_cost: 已计算的路径的总成本。


4.2 cost_index_path - 索引路径的成本估算

公式:

total_cost = indexStartupCost + indexTotalCost + cpu_index_tuple_cost * tuples

变量解释:

  • indexStartupCost: 索引路径的启动成本。

  • indexTotalCost: 索引路径的总成本。

  • cpu_index_tuple_cost: 每个元组的 CPU 成本。

  • tuples: 处理的元组数。


4.3 cost_bitmap_and_node - 位图 AND 节点的成本估算

公式:

total_cost = cpu_bitmap_and_cost

变量解释:

  • cpu_bitmap_and_cost: 位图 AND 操作的 CPU 成本。


4.4 cost_bitmap_or_node - 位图 OR 节点的成本估算

公式:

total_cost = cpu_bitmap_or_cost

变量解释:

  • cpu_bitmap_or_cost: 位图 OR 操作的 CPU 成本。


5. 其他相关辅助函数

5.1 get_reltuples - 获取关系的行数

公式:

reltuples = rel->rows

变量解释:

  • rel->rows: 估算的表中行数。


5.2 get_relwidth - 获取关系的宽度

公式:

relwidth = rel->reltarget->width

变量解释:

  • rel->reltarget->width: 表中每行的字节宽度。


5.3 clamp_row_est - 行估算值的限制

公式:

clamped_rows = max(min(rows, MAX_ROWS), MIN_ROWS)

变量解释:

  • rows: 估算的行数。

  • MAX_ROWS: 行数的最大合理值。

  • MIN_ROWS: 行数的最小合理值。

这些公式是 PostgreSQL 查询优化器评估不同查询执行计划成本的核心工具。它们根据特定查询操作的性质,结合系统参数和表的统计信息,计算出各种执行路径的成本,从而帮助优化器选择最优路径。

🛠️ 公式中的参数

PostgreSQL优化器的代价模型使用下面这些参数来估算每个算子的代价,这些参数默认值可能会因PostgreSQL的版本或特定的系统配置而有所不同。以下是基于PostgreSQL 14版本的常见默认值:

  1. seq_page_cost: 1.0

    • 含义: 顺序读取一个磁盘页面的成本

  2. random_page_cost: 4.0

    • 含义: 随机读取一个磁盘页面的成本

  3. cpu_tuple_cost: 0.01

    • 含义: 处理每个元组的CPU成本

  4. cpu_index_tuple_cost: 0.005

    • 含义: 处理每个索引元组的CPU成本

  5. cpu_operator_cost: 0.0025

    • 含义: 执行每个操作符或函数的CPU成本

  6. pages:

    • 含义: 表或索引的页面数,根据实际表或索引大小计算,没有固定默认值

  7. tuples:

    • 含义: 预计处理的元组数,基于表统计信息,没有固定默认值

  8. index_pages_fetched:

    • 含义: 预计读取的索引页面数,根据索引统计信息计算,没有固定默认值

  9. tuples_fetched:

    • 含义: 通过索引获取的元组数,根据查询条件和统计信息估算,没有固定默认值

  10. bitmap_pages:

    • 含义: 位图中的页面数,根据查询条件和统计信息估算,没有固定默认值

  11. tids_fetched:

    • 含义: 通过TID扫描获取的元组数,根据查询条件确定,没有固定默认值

重要的是要注意,这些成本参数(如seq_page_cost, random_page_cost等)是相对值,它们之间的比例关系比绝对值更重要。优化器使用这些值来比较不同执行计划的相对成本,从而选择最优计划。

您可以通过修改postgresql.conf文件或使用SET命令来调整这些参数,以更好地适应您的特定硬件和工作负载。在调整这些参数时,建议进行充分的测试,以确保更改确实提高了查询性能。

🌟 总结

  1. 基于统计信息

    • PostgreSQL 利用表和索引的统计信息(如行数、页面数、行宽度、唯一值数目等)来估算每种操作的成本。

  2. 成本的组成

    • 代价模型综合考虑了I/O成本(顺序扫描、随机读取)、CPU成本(处理行和执行操作符)以及其他初始化或启动成本,来估算每种查询操作的代价。

  3. 多路径评估

    • 对于每个查询,优化器会生成多种可行路径,并基于代价模型对这些路径进行评估,选择总成本最低的路径。

  4. 灵活性

    • 代价模型中的参数(如seq_page_costcpu_tuple_cost等)可以根据数据库的实际硬件环境和应用场景进行调优,以获得更好的查询性能。

通过这种代价模型,PostgreSQL 能够在复杂查询的多种执行路径中选择最优路径,确保高效的查询执行。

🌟关于PawSQL


PawSQL专注于数据库性能优化自动化和智能化,提供的解决方案覆盖SQL开发、测试、运维的整个流程,广泛支持MySQL、PostgreSQL、OpenGauss、Oracle等主流商用和开源数据库,以及openGauss,人大金仓、达梦等国产数据库,为开发者和企业提供一站式的创新SQL优化解决方案;有效解决了数据库SQL性能及质量问题,提升了数据库系统的稳定性、应用性能和基础设施利用率,为企业节省了大量的运维成本和时间投入。

图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/149004.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

数据脱敏-快速使用

1.数据脱敏定义 数据脱敏百度百科中是这样定义的: 数据脱敏,指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。 因为在真正的生产环境中,很多数据是不能直接返回,但是我们工作的时候可能经常性的需要返回一些用户信…

历年大厂校招 网络安全面试题(80+经验贴)

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 《Java代码审…

为什么要使用多线程

为什么要使用多线程 任务分解&#xff1a;耗时的操作&#xff0c;任务分解&#xff0c;实时响应。数据分解&#xff1a;充分利用多核CPU处理数据。数据流分解&#xff1a;读写分离&#xff0c;解耦合设计。 #include <iostream> #include<thread> using namespac…

【Unity编辑器扩展】解决uGUI动效痛点 零代码可视化快速制作UI动效 DOTween Sequence可视化

UI动效痛点&#xff1a; UI动效一直是Unity游戏开发的一大痛点&#xff0c;大部分项目都在使用Animator/Animation制作UI动效。而Animation是以节点路径记录动画&#xff0c;一旦UI层级、节点名变更就会导致动效返工&#xff0c;且Animation编辑器缓动曲线很难控制&#xff0c…

【论文速看】DL最新进展20240923-长尾综述、人脸防伪、图像分割

目录 【长尾学习】【人脸防伪】【图像分割】 【长尾学习】 [2024综述] A Systematic Review on Long-Tailed Learning 论文链接&#xff1a;https://arxiv.org/pdf/2408.00483 长尾数据是一种特殊类型的多类不平衡数据&#xff0c;其中包含大量少数/尾部类别&#xff0c;这些类…

C:内存函数

目录 前言&#xff1a; 一、memcpy 函数的使用及实现 1、memcpy函数的介绍 1.1 memcpy函数参数解读 2、memcpy函数的使用 3、memcpy函数的模拟实现 二、memmove函数的使用及模拟 1、memmove函数的使用 2、memmove函数的模拟实现 三、memset 函数的使用 1、memset函数的…

PyCharm下载和安装教程

Python、C/C、C#、DSL、Go、Groovy、Java、JavaScript、Objective-C、PHP 等编程语言。 图 1 JetBrains 开发工具 PyCharm下载和安装 进入 PyCharm官方下载页面(如图 2 所示)&#xff0c;可以看到 PyCharm 有 2 个版本&#xff0c;分别是 Professional(专业版)和 Community(社…

Mybatis百万数据插入(含导出)

1 一般一次性插入多条数据 传统的sql语句&#xff1a; INSERT INTO table1 ( field1, field2 ) VALUES( "data1", "data2" ); INSERT INTO table1 ( field1, field2 ) VALUES( "data1", "data2" ); INSERT INTO table1 ( field1, fi…

DirectX修复助手

在日常使用电脑时&#xff0c;我们可能会遇到提示缺少DLL文件&#xff0c;如0xc000007b错误、缺少d3dxxx.dll等问题&#xff0c;这些会影响软件运行甚至导致系统不稳定。以下是一些常见的DLL问题原因和一个修复工具&#xff0c;希望能帮到你。 DLL文件问题的常见原因 软件安装…

20 基于STM32的温度、电流、电压检测proteus仿真系统(OLED、DHT11、继电器、电机)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STM32F103C8T6 采用DHT11读取温度、滑动变阻器模拟读取电流、电压。 通过OLED屏幕显示&#xff0c;设置电流阈值为80&#xff0c;电流小阈值为50&#xff0c;电压阈值为60&#xff0c;温度阈值…

24. Revit API: 几何对象(五)- (Sur)Face

一、前言 虽然Face是GeometryObject的子类&#xff0c;Surface不是&#xff0c;但这两者之间还是挺有关联的&#xff0c;每个Face都有一个对应的Surface&#xff0c;类似于Edge和Curve的关系。 Surface是数学意义上的面&#xff0c;纯定义。 Face是几何形状&#xff08;实体&a…

css如何设置间距

在CSS中设置间距是非常常见的需求&#xff0c;可以通过多种属性来实现。以下是一些常用的CSS属性及其用法&#xff0c;用于设置元素之间的间距&#xff1a; 内边距&#xff08;Padding&#xff09; padding 属性用于设置元素内容与元素边框之间的距离。可以分别设置四个方向的…

视频质量评价SimpleVQA

目录 一、研究意义 例子 二、介绍 三、文章解读 3.1 论文动机 3.2论文思路 3.3方法 3.3.1网络框架 3.3.2公式解读 3.3.3核心创新 3.3.4理解 &#xff01;&#xff01;&#xff01;作者对模型的改进 本人算法框体 3.3.5实验细节&#xff1a; 四、代码复现 4.1代码文件简介 4.2数…

leetcode第二十六题:删去有序数组的重复项

给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff0c;你…

C++之STL—vector容器基础篇

头文件 #include <vector> //vector容器 #include <algorithm> //算法 基本用法&&概念 vector<int> v; v.push_back(10); vector<int >::iterator v.begin(); v.end(); 三种遍历方式 #include <vector> #include <algorithm>…

Leetcode3289. 数字小镇中的捣蛋鬼

Every day a Leetcode 题目来源&#xff1a;3289. 数字小镇中的捣蛋鬼 解法1&#xff1a;哈希 代码&#xff1a; /** lc appleetcode.cn id3289 langcpp** [3289] 数字小镇中的捣蛋鬼*/// lc codestart class Solution { public:vector<int> getSneakyNumbers(vector…

在线文档搜索服务测试报告

目录 1. 项目背景: 2. 项目功能: 3. 测试计划: 1. 项目背景: 1.1 在线搜索服务的前端主要一下几个功能, 分别是进入搜索引擎界面(有提示输入关键词信息); 进行输入关键词的界面, 以及显示有关关键词的文档url, 点击跳转至目标文档的界面; 1.2 该在线搜索服务的文档可以实现用…

精彩回顾|博睿数据Bonree ONE 3.0产品发布会圆满落幕:三城联动 共襄盛举!

在金秋九月的璀璨时刻&#xff0c;博睿数据于9月20日在北京圆满举办了Bonree ONE 3.0产品发布会的收官之站。此前&#xff0c;这一盛会已在上海、广州相继绽放光彩&#xff0c;三城联动&#xff0c;共襄盛举&#xff0c;不仅展现了博睿数据在可观测性领域的深厚积淀与前瞻视野&…

一行命令,一分钟轻松搞定SSL证书自动续期

httpsok 是一个便捷的 HTTPS 证书自动续签工具&#xff0c;专为 Nginx 服务器设计。已服务众多中小企业&#xff0c;稳定、安全、可靠。现在的网站SSL免费证书有效期只有3个月&#xff0c;所以就会有经常更快SSL证书的需求&#xff0c;如果手上需要更换的SSL证书比较多的情况下…

leetcode第80题:删除有序数组的重复项(||)

给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 说明&…