pg 统计信息及索引cost 简介

2024-04-30 22:04
文章标签 统计 索引 信息 简介 pg cost

本文主要是介绍pg 统计信息及索引cost 简介,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

pg 统计信息及索引cost 简介

  • pg 统计信息及索引cost 简介
    • 单列的统计信息
      • 数据采样
        • 对于外部表:
      • 数据统计
    • 索引cost 计算
    • 行数确定

pg 统计信息及索引cost 简介

单列的统计信息

单列的统计信息,通过do_analyze_rel 函数进行生成,主要分为两个部分:

  1. 数据采样
  2. 数据统计

数据采样

随机的采取表中的一部分数据进行分析,如果没有指定采样数(一般都没有),使用default_statistics_target (默认100)进行计算,采样容量为 300 * default_statistics_target (默认30000)。

根据 SIGMOD98 中的论文 Random sampling fo r histogram construction: how much is enough 可以得出这个这个已足够,当当表很大是,仍需调大default_statistics_target 。

采样算法采样两阶段算法,第一阶段采样使用S算法对表中的页面进行随机采样,第二个阶段使用 Z(Vitter)算法,它在第一阶段采样出来的页面的基础上对元组进行采样。

数据采样的两个阶段采用不同的算法是因为当对一个表进行统计分析的时候,它的页面数(块数)是可以准确获得到的,也就是说页面采样是在己知总体容量的基础上进行的。而第二阶段的 Z(Vitter)算法是一种蓄水池算法,它主要解决的是在不知道总体容量的情况下如何进

对于外部表:
  • pg: 通过AnalyzeForeignTable 函数获取采样外部表的函数acquirefunc(没有则warning,同时也获取relpages),然后调用函数获取采样的行,然后对数据进行统计
  • opengauss :通过AnalyzeForeignTable 函数获取采样外部表的函数acquirefunc(没有则warning,同时也获取relpages),但gauss 不使用acquirefunc 获取行, 而是通过AcquireSampleRows采样行(只支持obs,hdfs, obs_cvs, oracle_fdw,pg_fdw,mot,RELKIND_STREAM?支持其他的需要修改代码)

数据统计

分析各个列的统计信息, 对于表达式索引,也会计算表达式值并统计信息。

统计数据会存在pg_statistic 表中,

pages/tuples 会计入对应的表和索引中(Update pages/tuples stats in pg_class, 默认表和索引的行数相同,除非是partial index - 带where条件的索引 )

索引不会使用采样到的pages ,因为这个pages 是表的pages. 而是使用GetOneRelNBlocks 获取的blocks, 作为pages. 对于外表就是0

索引cost 计算

cpu 和 io , 选择率用来确定行数或索引项数

对于seqscan, 选择率用来确定 返回的行数

对于索引扫描,会调用索引的amcostestimate 函数计算索引cost和索引项数目,索引条件的选择率(其实就是列的选择率)用来确定扫描到的索引项数,会基于这个索引项数确定对堆表的io 和cpu cost (pg 索引不是聚簇索引,需要回表查询,除非indexonly)

    amcostestimate:/** @param loop_count 索引作为内表时,需要循环的次数* @[out]indexStartupCost 索引扫描自身的启动代价* @[out]indexTotalCost 索引扫描自身的整体代价* @[out]indexSelectivity 索引扫描的选择率* @[out]indexCorrelation 索引的相关系数* @[out]indexPages 索引page 数,opengauss 没有* */void (*amcostestimate)(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost,Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation,double *indexPages)

在btree 中,启动代价为约束中的表达式代价,即计算所有的表达式值的代价(因为在每次扫描前需要计算表达式的值,右值)。

总代价为 io代价和 cpu代价的和。

  • io代价: 索引扫描的执行次数取决于外表的元组数和是否有ScalarArrayOpExpr(有那么num_sa_scans也是扫描次数),所以num_scans = num_sa_scans * num_outer_scans;因为多次扫描可能导致数据被缓存,所以通过如下方式计算IO cost:
        /*   对于外表:在pg 中,index->pages 为0在 opengauss 中,在 build_simple_rel 中会调用 set_local_rel_size,最终调用clamp_row_est 会把index->pages 转换为1, 也即外表上的索引 index->pages 为1*/if (index->pages > 1 && index->tuples > 1)numIndexPages = ceil(numIndexTuples * index->pages / index->tuples);elsenumIndexPages = 1.0;   // numIndexPages 如果小于1 会被设置为1,对于外表即为1double		pages_fetched;/* total page fetches ignoring cache effects */pages_fetched = numIndexPages * num_scans;/* use Mackert and Lohman formula to adjust for cache effects */pages_fetched = index_pages_fetched(pages_fetched,index->pages,(double) index->pages,root);/** Now compute the total disk access cost, and then report a pro-rated* share for each outer scan.  (Don't pro-rate for ScalarArrayOpExpr,* since that's internal to the indexscan.)*/indexTotalCost = (pages_fetched * spc_random_page_cost)/ num_outer_scans;

非多次扫描:indexTotalCost = numIndexPages * spc_random_page_cost;

  • CPU cost:
        qual_op_cost = cpu_operator_cost *(list_length(indexQuals) + list_length(indexOrderBys));indexTotalCost += qual_arg_cost;  //  加上start_cost,qual_arg_cost即start costindexTotalCost += numIndexTuples * num_sa_scans * (cpu_index_tuple_cost + qual_op_cost);  // 加上每个索引项的cpu costopengauss 没有下面的cost:b tree查找非叶子节点的cost:if (index->tuples > 1)		/* avoid computing log(0) */{descentCost = ceil(log(index->tuples) / log(2.0)) * cpu_operator_cost;costs.indexStartupCost += descentCost;costs.indexTotalCost += costs.num_sa_scans * descentCost;}b tree对节点的page 进行二分查找的cost:descentCost = (index->tree_height + 1) * 50.0 * cpu_operator_cost;costs.indexStartupCost += descentCost;costs.indexTotalCost += costs.num_sa_scans * descentCost;
  • 相关系数:单列的通过pg_statistic 获取

行数确定

通过调用get_relation_info (add_base_rels_to_query)获取表及表上索引的page 和行数, 对于表调用estimate_rel_size 获取,对于非部分索引,page 通过RelationGetNumberOfBlocks 获取, tuples 即为表的tuples。 部分索引通过estimate_rel_size 获取,但如果获取的行数大于表的行数,则tuples 设置为表行数。

estimate_rel_size 会去获取关系的blocks ,然后计算pages 和tuples, 之后在make_one_rel 中会调用set_base_rel_sizes 调整rows, 宽度

  • 外表:
        static voidset_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte){/* Mark rel with estimated output rows, width, etc */set_foreign_size_estimates(root, rel);/* Let FDW adjust the size estimates, if it can */rel->fdwroutine->GetForeignRelSize(root, rel, rte->relid);/* ... but do not let it set the rows estimate to zero */rel->rows = clamp_row_est(rel->rows);/* also, make sure rel->tuples is not insane relative to rel->rows */rel->tuples = Max(rel->tuples, rel->rows);}
  • 普通表:
        voidset_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel){double		nrows;/* Should only be applied to base relations */Assert(rel->relid > 0);nrows = rel->tuples *clauselist_selectivity(root,rel->baserestrictinfo,0,JOIN_INNER,NULL);rel->rows = clamp_row_est(nrows);cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo, root);set_rel_width(root, rel);}

这篇关于pg 统计信息及索引cost 简介的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/950038

相关文章

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

MySQL逻辑删除与唯一索引冲突解决方案

《MySQL逻辑删除与唯一索引冲突解决方案》本文探讨MySQL逻辑删除与唯一索引冲突问题,提出四种解决方案:复合索引+时间戳、修改唯一字段、历史表、业务层校验,推荐方案1和方案3,适用于不同场景,感兴... 目录问题背景问题复现解决方案解决方案1.复合唯一索引 + 时间戳删除字段解决方案2:删除后修改唯一字

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu

浅谈mysql的not exists走不走索引

《浅谈mysql的notexists走不走索引》在MySQL中,​NOTEXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引,下面就来介绍一下mysql的notexists走不走索... 在mysql中,​NOT EXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引。以下

Qt QCustomPlot库简介(最新推荐)

《QtQCustomPlot库简介(最新推荐)》QCustomPlot是一款基于Qt的高性能C++绘图库,专为二维数据可视化设计,它具有轻量级、实时处理百万级数据和多图层支持等特点,适用于科学计算、... 目录核心特性概览核心组件解析1.绘图核心 (QCustomPlot类)2.数据容器 (QCPDataC

MySQL之InnoDB存储引擎中的索引用法及说明

《MySQL之InnoDB存储引擎中的索引用法及说明》:本文主要介绍MySQL之InnoDB存储引擎中的索引用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录1、背景2、准备3、正篇【1】存储用户记录的数据页【2】存储目录项记录的数据页【3】聚簇索引【4】二

全面解析MySQL索引长度限制问题与解决方案

《全面解析MySQL索引长度限制问题与解决方案》MySQL对索引长度设限是为了保持高效的数据检索性能,这个限制不是MySQL的缺陷,而是数据库设计中的权衡结果,下面我们就来看看如何解决这一问题吧... 目录引言:为什么会有索引键长度问题?一、问题根源深度解析mysql索引长度限制原理实际场景示例二、五大解决

在Linux终端中统计非二进制文件行数的实现方法

《在Linux终端中统计非二进制文件行数的实现方法》在Linux系统中,有时需要统计非二进制文件(如CSV、TXT文件)的行数,而不希望手动打开文件进行查看,例如,在处理大型日志文件、数据文件时,了解... 目录在linux终端中统计非二进制文件的行数技术背景实现步骤1. 使用wc命令2. 使用grep命令