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数据库中,我们都清楚统计信息对于优化器来说非常重要,所以本文就来和大家简单聊一聊SQLServer如何跟踪自动统计信息更新吧... SQL Server数据库中,我们都清楚统计信息对于优化器来说非常重要。一般情况下,我们会开启"自动更新

Python如何获取域名的SSL证书信息和到期时间

《Python如何获取域名的SSL证书信息和到期时间》在当今互联网时代,SSL证书的重要性不言而喻,它不仅为用户提供了安全的连接,还能提高网站的搜索引擎排名,那我们怎么才能通过Python获取域名的S... 目录了解SSL证书的基本概念使用python库来抓取SSL证书信息安装必要的库编写获取SSL证书信息

Win32下C++实现快速获取硬盘分区信息

《Win32下C++实现快速获取硬盘分区信息》这篇文章主要为大家详细介绍了Win32下C++如何实现快速获取硬盘分区信息,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 实现代码CDiskDriveUtils.h#pragma once #include <wtypesbase

Mysql中InnoDB与MyISAM索引差异详解(最新整理)

《Mysql中InnoDB与MyISAM索引差异详解(最新整理)》InnoDB和MyISAM在索引实现和特性上有差异,包括聚集索引、非聚集索引、事务支持、并发控制、覆盖索引、主键约束、外键支持和物理存... 目录1. 索引类型与数据存储方式InnoDBMyISAM2. 事务与并发控制InnoDBMyISAM

StarRocks索引详解(最新整理)

《StarRocks索引详解(最新整理)》StarRocks支持多种索引类型,包括主键索引、前缀索引、Bitmap索引和Bloomfilter索引,这些索引类型适用于不同场景,如唯一性约束、减少索引空... 目录1. 主键索引(Primary Key Index)2. 前缀索引(Prefix Index /

MySQL进阶之路索引失效的11种情况详析

《MySQL进阶之路索引失效的11种情况详析》:本文主要介绍MySQL查询优化中的11种常见情况,包括索引的使用和优化策略,通过这些策略,开发者可以显著提升查询性能,需要的朋友可以参考下... 目录前言图示1. 使用不等式操作符(!=, <, >)2. 使用 OR 连接多个条件3. 对索引字段进行计算操作4

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

Java实现Elasticsearch查询当前索引全部数据的完整代码

《Java实现Elasticsearch查询当前索引全部数据的完整代码》:本文主要介绍如何在Java中实现查询Elasticsearch索引中指定条件下的全部数据,通过设置滚动查询参数(scrol... 目录需求背景通常情况Java 实现查询 Elasticsearch 全部数据写在最后需求背景通常情况下

Pandas中多重索引技巧的实现

《Pandas中多重索引技巧的实现》Pandas中的多重索引功能强大,适用于处理多维数据,本文就来介绍一下多重索引技巧,具有一定的参考价值,感兴趣的可以了解一下... 目录1.多重索引概述2.多重索引的基本操作2.1 选择和切片多重索引2.2 交换层级与重设索引3.多重索引的高级操作3.1 多重索引的分组聚

C#实现系统信息监控与获取功能

《C#实现系统信息监控与获取功能》在C#开发的众多应用场景中,获取系统信息以及监控用户操作有着广泛的用途,比如在系统性能优化工具中,需要实时读取CPU、GPU资源信息,本文将详细介绍如何使用C#来实现... 目录前言一、C# 监控键盘1. 原理与实现思路2. 代码实现二、读取 CPU、GPU 资源信息1.