PostgreSQL 中统计信息计算

(点击上方蓝字,快速关注我们)


来源:伯乐在线 - Rings

链接:http://blog.jobbole.com/106612/


#0. 前言背景


在PostgreSQL中当我们查询引擎在生成执行计划时候,一个重要的问题是如何才能使得我们所生成的执行计划是一个最优的结果。考虑到执行计划最终需要与磁盘进行IO操作以读取相应的数据,因此如果使得我们所生成的执行计划其代价最优,这便是查询引擎在查询优化过程中需要考虑的一个问题。而执行代价又包括两个方面:(1)计算资源;(2)IO资源。其中:计算资源主要涉及到CPU的计算时间,而IO资源主要包括磁盘的访问资源等(这两类资源具体包括哪些,在这里就不在详述了。)


对于一条查询语句来说,其最终会落到磁盘的读写上面,因此衡量一个查询引擎的好坏的标准是:是否可以将IO开销做到最少。例如:对于查询语句 SELECT * FROM tenk1 WHERE stringu1 = ‘xxx’; 其有无索引对于执行计划有着不同的影响。


#1. 统计信息


(1) 元数据表 pg_statistic 和 pg_stats


对于pg_statistic里面保存了关于某个表的相关统计信息,比如:该表的所有的Page数据和tuples数据量。 为了防止为授权用户能够修改其中的数据(pg_statistic只能由管理员来访问,而pg_stat是视图可由非管理员用户查看数据。)。当planner需要统计数据时候其会从该表中获取,而并不是执行真正的表扫描,前提是对该表执行了analyze操作后。 relpages,reltuples, 当relpages发生变化后,在不执行analyze的情况会根据上一次relpage与reltuples的比例关系进行适当的变更。


对于selectivity 即:where子句中的选择率(该值描述了在一张表里面,对于某个值的区分度)。该选择由 pg_operator中来进行查找获取相应的selectivity。其由pg_operator中的oprrest属性所对应的函数来描述。 然后由该函数从pg_statistic中取出条件属性相应的柱状图统计进行(historgram)。


例如:


SELECT histogram_bounds FROM pg_stats

WHERE tablename='tenk1' AND attname='unique1';

histogram_bounds

------------------------------------------------------

{0,993,1997,3050,4040,5036,5957,7057,8029,9016,9995}


对于语句:


SELECT * FROM tenk1 WHERE unique1 < 1000;


其中1000在第二个桶里面,[993 1997],假设在在每个桶里的数据是线性分布的。因此我们可以计算 < 1000时候的分布概率。


因此相应的概率分布为:


selectivity = (1 + (1000 – bucket[2].min)/(bucket[2].max – bucket[2].min))/num_buckets

= (1 + (1000 – 993)/(1997 – 993))/10

= 0.100697


相应的计算公式 选择率的:


[Num(No. (X-1)) + (N- X.min)/(X.max-X.min)]/ NumOfBucket


然后相应的满足条件的记录数: rows = rel_cardinality * selectivity , 其中 rel_cardinality是该表中的记录基数。即表中总共有多少记录数。 对于等号,其柱状图的估计对于等号,其有效性不如其他操作。此时,我们使用最常用值来进行估计。在pg_stats中,我们根据表名和属性名来查询出 most_common_freqs,most_common_vals来。


例如:


“{1,100,10}”;”


对应的freqs


{0.97588,0.0126532,0.0106762}”


例如:对于SELECT * FROM tenk1 WHERE stringu1 = ‘xxx’; 查询语句, 当我们常量 xxx 属于 most common value时候,我们就可以使用该值对应的most common freqs作为该值的selectivity,但是当该值不在mcv列表里面时候,此时的selectivity的估算就不能简单的使用mcv列表里面的值。 此时,需要一个新的计算方式来完成对非条件不在mcv列表中的情况。我们采用的是将现有的知识进行想融合的方式来进行选择率的估计。


selectivity = (1 – sum(mvf))/(num_distinct – num_mcv)


该中方式下,将所有的most common freqs求和后,然后计算其与1直接的差值,由此我们可以知道:在均匀分布的情况下,如果条件为非mvc情况下,其most common freqs的值就为 (1- sum (msf))。对于该值的选择率,我们此概率与整个最优的值的分布之间的比例。


对于之前的 SELECT * FROM tenk1 WHERE unique1 < 1000; 过于简单。当条件列为mcv列表中的时候可以使用上述的计算方式,当时当条件列不在mcv列表中的时候,对于非唯一的列,其可以是柱状图或者mcv列表,且在柱状图中其并未包括哪些在mcv列表中所表示的那些元组数量。当此种情况下,我们将选择条件,应用于mcv列表中的所以值,并且将所有满足该条件的所有的mcf值相加。


例如:对于查询语句 SELECT * FROM tenk1 WHERE stringu1 < ‘IAAAAA’;


其相应的柱状图信息如下(我们可以从pg_stats进行查询获得):

pg_stats WHERE tablename='tenk1' AND attname='stringu1';

 

histogram_bounds

--------------------------------------------------------------------------------

{AAAAAA,CQAAAA,FRAAAA,IBAAAA,KRAAAA,NFAAAA,PSAAAA,SGAAAA,VAAAAA,XLAAAA,ZZAAAA}


当对于条件中存在着连接操作时候的选择率的估计与之前的做法相似。


例如对于查询语句:


SELECT * FROM tenk1 t1,tenk2 t2 WHERE t1.unique1 < 50 AND t1.unique2 = t2.unique2;


首先会计算条件 t1.unique1 < 50的选择率,对于该条件的选择率的计算参照上面讨论。


在文件src/backend/optimizer/util/plancat.c中计算一个表的大小(在任何的where子句之前),计算子句的选择率的由src/backend/optimizer/path/clausesel.c,关于操作符的选择率的计算则由src/backend/utils/adt/selfuncs.c中的函数来完成。


当我们计算一个语句的选择率时候,如果该语句存在着子句时候,我们就将这些子句的选择率先计算出来,然后分别计算这些子句的选择率,然后将这些子句的选择相乘从而获得整个语句的选择率,前提条件是这些子句其有这相互独立的概率条件,这与我们在概率论中的,两个事件是相互独立的事件时候,我们计算该这两个事件的概率相似。但是在现实世界中,这些却是不容易满足的条件,因此我们需要根据合理的计算方式来计算一个语句的选择率。


当然,对于统计信息,由于其它是基于估算的基础上,因此必然会存在着一个不可回避的问题:该统计信息的准确性(或者说不确定性),以及由此不准确所带来的问题,导致查询引擎在基于该统计信息计算最优查询访问路径时候的偏差(更加准确的是查询计划的“漂移”问题)。



关注「数据库开发」

看更多精选数据库技术文章

↓↓↓

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读601次。Oracle的数据导入导出是一项基本的技能,但是对于懂数据库却不熟悉Oracle的同学可能会有一定的障碍。正好在最近的一个项目中碰到了这样一个任务,于是研究了一下Oracle的数据导入导出,在这里跟大家分享一下。......_oracle 迁移方法 对比
文章浏览阅读553次。开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共700多人左右 1 + 2)。最近我们在使用MYSQL 8 的情况下(8.025)在数据库运行中出现一个问题 参数prefer_order_i..._mysql prefer_ordering_index
文章浏览阅读3.5k次,点赞3次,收藏7次。折腾了两个小时多才成功连上,在这分享一下我的经验,也仅仅是经验分享,有不足的地方欢迎大家在评论区补充交流。_navicat连接opengauss
文章浏览阅读2.7k次。JSON 代表 JavaScript Object Notation。它是一种开放标准格式,将数据组织成中详述的键/值对和数组。_postgresql json
文章浏览阅读2.9k次,点赞2次,收藏6次。navicat 连接postgresql 注:navicat老版本可能报错。1.在springboot中引入我们需要的依赖以及相应版本。用代码生成器生成代码后,即可进行增删改查(略)安装好postgresql 略。更改配置信息(注释中有)_mybatisplus postgresql
文章浏览阅读1.4k次。postgre进阶sql,包含分组排序、JSON解析、修改、删除、更新、强制踢出数据库所有使用用户、连表更新与删除、获取今年第一天、获取近12个月的年月、锁表处理、系统表使用(查询所有表和字段及注释、查询表占用空间)、指定数据库查找模式search_path、postgre备份及还原_pgsql分组取每组第一条
文章浏览阅读3.3k次。上一篇我们学习了日志清理,日志清理虽然解决了日志膨胀的问题,但就无法再恢复检查点之前的一致性状态。因此,我们还需要日志归档,pg的日志归档原理和Oracle类似,不过归档命令需要自己配置。以下代码在postmaster.c除了开启归档外,还需要保证wal_level不能是MINIMAL状态(因为该状态下有些操作不会记录日志)。在db启动时,会同时检查archive_mode和wal_level。以下代码也在postmaster.c(PostmasterMain函数)。......_postgresql archive_mode
文章浏览阅读3k次。系统:ubuntu22.04.3目的:利用向日葵实现windows远程控制ubuntu。_csdn局域网桌面控制ubuntu
文章浏览阅读1.6k次。表分区是解决一些因单表过大引用的性能问题的方式,比如某张表过大就会造成查询变慢,可能分区是一种解决方案。一般建议当单表大小超过内存就可以考虑表分区了。1,继承式分区,分为触发器(trigger)和规则(rule)两种方式触发器的方式1)创建表CREATE TABLE "public"."track_info_trigger_partition" ( "id" serial, "object_type" int2 NOT NULL DEFAULT 0, "object_name..._pg数据表分区的实现
文章浏览阅读3.3k次。物联网平台开源的有几个,就我晓得的有、、thingskit、JetLink、DG-iot(还有其他开源的,欢迎在评论区留言哦!),然后重点分析了下ThingsBoard、ThingsPanel和JetLink,ThingsBoard和Jetlinks是工程师思维产品,可以更多的通过配置去实现开发的目的,ThingsPanel是业务人员思路产品,或者开发或者用,避免了复杂的配置带来的较高学习门槛。ThingsBoard和Jetlinks是Java技术体系的,ThingsPanel是PHP开发的。_jetlinks和thingsboard
文章浏览阅读3.8k次。PostgreSQL 数据类型转换_pgsql数字转字符串
文章浏览阅读7k次,点赞3次,收藏14次。在做数据统计页面时,总会遇到统计某段时间内,每天、每月、每年的数据视图(柱状图、折线图等)。这些统计数据一眼看过去也简单呀,不就是按照时间周期(天、月、年)对统计数据进行分个组就完了嘛?但是会有一个问题,简单的写个sql对周期分组,获取到的统计数据是缺失的,即没有数据的那天,整条记录也都没有了。如下图需求:以当前月份(2023年2月)为起点,往后倒推一年,查询之前一年里每个月的统计数据。可见图中的数据其实是缺少的,这条sql只查询到了有数据的月份(23年的1月、2月,22年的12月)_如何用一条sql查出按年按月按天的汇总
文章浏览阅读3.8k次,点赞66次,收藏51次。PostgreSQL全球开发小组与2022年10月13日,宣布发布PostgreSQL15,这是世界上最先进的开源数据库的最新版本_mysql8 postgresql15
文章浏览阅读1.3k次。上文介绍了磁盘管理器中VFD的实现原理,本篇将从上层角度讲解磁盘管理器的工作细节。_smgrrelationdata
文章浏览阅读1.1k次。PostgreSQL设置中文语言界面和局域网访问_postgressql汉化
文章浏览阅读4.2k次。PostgreSQL 修改数据存储路径_如何设置postgresql 数据目录
文章浏览阅读4.7k次。在项目中用到了多数据源,在连接postgres数据库时,项目启动报错,说数据库连接错误,说dual不存在,网上好多教程都是说数据库查询的时候的大小写问题,而这个仅仅是连接,咋鞥却处理方法是修改application-dev.yml中的配置文件.项目中的druid参数是这样的:确实在配置文件中有个查询语句。_relation "dual" does not exist
文章浏览阅读4.9k次。PostgreSQL是一款强大的关系型数据库,但在实际使用过程中,许多用户经常会遇到慢SQL的问题。这些问题不仅会降低数据库性能,还会直接影响业务流程和用户体验。因此,本文将会深入分析PostgreSQL慢SQL的原因和优化方案,帮助用户更好地利用这个优秀的数据库系统。无论你是初学者还是专业开发者,本文都将为你提供实用的技巧和方法,让你的PostgreSQL数据库始终保持高效快速。_postgresql数据库优化
文章浏览阅读1.6k次。Linux配置postgresql开机自启_linux 启动pgsql
文章浏览阅读2k次。本篇介绍如何在centos7系统搭建一个postgresql主备集群实现最近的HA(高可用)架构。后续更高级的HA模式都是基于这个最基本的主备搭建。_postgresql主备