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

相关文章

Java Docx4j类库简介及使用示例详解

《JavaDocx4j类库简介及使用示例详解》Docx4j是一个强大而灵活的Java库,非常适合需要自动化生成、处理、转换MicrosoftOffice文档的服务器端或后端应用,本文给大家介绍Jav... 目录1.简介2.安装与依赖3.基础用法示例3.1 创建一个新 DOCX 并添加内容3.2 读取一个已存

一文详解MySQL索引(六张图彻底搞懂)

《一文详解MySQL索引(六张图彻底搞懂)》MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度,:本文主要介绍MySQL索引的相关资料,文中通过代码介绍的... 目录一、什么是索引?为什么需要索引?二、索引该用哪种数据结构?1. 哈希表2. 跳表3. 二叉排序树4.

linux查找java项目日志查找报错信息方式

《linux查找java项目日志查找报错信息方式》日志查找定位步骤:进入项目,用tail-f实时跟踪日志,tail-n1000查看末尾1000行,grep搜索关键词或时间,vim内精准查找并高亮定位,... 目录日志查找定位在当前文件里找到报错消息总结日志查找定位1.cd 进入项目2.正常日志 和错误日

Java中最全最基础的IO流概述和简介案例分析

《Java中最全最基础的IO流概述和简介案例分析》JavaIO流用于程序与外部设备的数据交互,分为字节流(InputStream/OutputStream)和字符流(Reader/Writer),处理... 目录IO流简介IO是什么应用场景IO流的分类流的超类类型字节文件流应用简介核心API文件输出流应用文

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示

PostgreSQL简介及实战应用

《PostgreSQL简介及实战应用》PostgreSQL是一种功能强大的开源关系型数据库管理系统,以其稳定性、高性能、扩展性和复杂查询能力在众多项目中得到广泛应用,本文将从基础概念讲起,逐步深入到高... 目录前言1. PostgreSQL基础1.1 PostgreSQL简介1.2 基础语法1.3 数据库

IDEA与MyEclipse代码量统计方式

《IDEA与MyEclipse代码量统计方式》文章介绍在项目中不安装第三方工具统计代码行数的方法,分别说明MyEclipse通过正则搜索(排除空行和注释)及IDEA使用Statistic插件或调整搜索... 目录项目场景MyEclipse代码量统计IDEA代码量统计总结项目场景在项目中,有时候我们需要统计

Python库 Django 的简介、安装、用法入门教程

《Python库Django的简介、安装、用法入门教程》Django是Python最流行的Web框架之一,它帮助开发者快速、高效地构建功能强大的Web应用程序,接下来我们将从简介、安装到用法详解,... 目录一、Django 简介 二、Django 的安装教程 1. 创建虚拟环境2. 安装Django三、创