PostgreSQL 执行计划,成本公式解说,代价因子校准,自动跟踪SQL执行计划(二)|学习笔记

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: 快速学习PostgreSQL 执行计划,成本公式解说,代价因子校准,自动跟踪SQL执行计划(二)

开发者学堂课程【PostgreSQL快速入门: PostgreSQL 执行计划,成本公式解说,代价因子校准,自动跟踪SQL执行计划(二)】学习笔记与课程紧密联系,让用户快速学习知识

课程地址https://developer.aliyun.com/learning/course/16/detail/91


PostgreSQL 执行计划,成本公式解说,代价因子校准,自动跟踪SQL执行计划(二)

 

内容介绍:

四、EXPLAIN 成本计算

五、EXPLAIN 行数评估

六、EXPLAIN 成本计算-索引扫描


四、EXPLAIN 成本计算

1、跟 explain 成本相关的有表或视图,列了 pg_stata 视图和 pg_class 表,pg_class 表里面有两个跟成本计算相关的,分别是是 relpages 和 reluples。relpages 表示这个表占用多少页面,reluples 表示总共有多少条记录。

举个例子看一下,select count(*)from u,u表没有记录。

看一下 t1 表,t1 表有记录,先搜集它的信息。

image.png

新建一个表,create table test1〈id int〉,insert into test1 select generate_series〈1,00000〉,往里面插入十万条记录,analyze test1,这样统计信息就收集了。

select *  from pg_class where oid=`test1`:: regclass,

reltuplss 有十万条记录,有443个页面(relpages),总共占了443个页和十万条记录,这可以拿来做成本计算。

2假如做一个全表扫描,成本很容易计算出来,一个是 reltuples,就是 cpu 的 tuples cost,是100000×CPU tuples cost 的因子,relpages 是443,443乘以连续扫描每个页面的成本因子。select count(*)from test1

image.png

这里也是 cost,其实来自于 cpu tuples costrelpages cost。show seq_page_cost 代价是1,cpu_tuple_cost 代价是0.01,所以它的成本等于是 seqcost乘以443 个数据块,再加上十万条记录乘以0.01,这就是最终的代价1443,这是全表扫描的如何计算成本。如果是对于很复杂的扫描,比如说索引或带 复杂的 where 条件,就要用到 pg_status 统计信息,并且还要用到下面的代价因子。

seq_page_cost --全表扫描的单个数据块的代价因子

random_page_cost --索引扫描的单个数据块的代价因子 cpu_tuple_cost –理每条记录的 CPU 开销代价因子

cpu_index_tuple_cost -- 索引扫描时每个索引条目的CPU开销代价因子

cpu_operator_cost--操作符或函数的开销代价因子

假如有一个 where 条件,where id<100,小于号就是一个 operate,它是额外带来的 CPU 的开销。除了全表扫描之外,还有额外的开销,就是小于100的开销。

image.png

select * from pg_operate where oprname=‘<’ 看小于号对应的是哪种函数,小于号有很多操作,有很多类型,这里是 int 型。select oid from pg_type where typname =‘integer’,select oid from pg_type where typname =‘int4’,int4 的oid 是23重新查一下 operate 表,operate 左右都是23,

image.png

select * from pg_operate where oprname=‘<’ and oprleft=23 and oprright=23,对应的是 int4lt 函数,oprcode 对应的是 int4lt 函数,select * from pg_proc where proname=‘int4lt’,这个函数的成本(procost)是1。每一条记录上面都会额外带来1乘以cpu_operate_cost 的开销cpu_operate_cost是0.025它的成本变成了 1*443+100000*0.01+0.025*1*100000,这样就得到1693了,也就是下图看到的1693。

image.png

3、知道简单的公式之后,看一下复杂的。pg_stats 是用于复杂的查询里,会用到下面的统计信息,

image.png

这些统计信息非常全面,schemaname 表示 pg_stats 统计信息的对象放在哪个 schema 下;tablename 统计信息对象是哪个表名;attname 统计信息对应的是哪个列,列指的是对应到的统计信息。比如说 test1 表上有一个 id 键,select * from pg_stats where tablename=‘test1’ and attname=‘id’,这样就输出了一条它的统计信息。

image.png

对着上图分解一下意思。

inherited 指的是这条统计信息是否包含子表的列,如pg_stats 表有子表的话,创建了另外一个表叫 test2,Inherited test1,有一个子表。

null_frac 指的是这个 id 有百分之多少的行是空值,0%表示所有的都是非空的。

avg_width 指的是平均列的长度,它是一个 int 类型,有4个字节。n_distinct 指的是百分之多少的值是唯一值,有多少行就有多少唯一值,这里插入的值是1到10万,全都是唯一值。

most_common_vals 指最频繁出现的是哪些值,这个字段存进去的都是完全唯一,所以不可能有 most_common_vals,也不可能有 most_common_freqs。test1 表上面的 id 字段的每一行都是不一样的,所以没有哪些值是比较频繁的,频度也是空。

4、hisrogram_bounds 代表的是这个字段上面做了一些 bucket,它的数据分布在 bucket 里面每一个数据分布的百分比一样,bucket 有多大跟一个参数有关,bucket 的大小和

default_statistics_target 有关,如果这个表定义了一个新的 statistics target,它的柱状图可以改变。现在有100个 bucket,就是有100个这样的间隔,1到1012是一个间隔,1012到2091又是一个间隔,相当于有100个篮子,每个篮子里面从1到1012之间的值有多少条记录跟1012到2091之间有多少条记录是一样的,同时跟99012到99997也是一样的。

correlation 指的是数据的存储顺序和字段值的排序是否一样?这里存进去的值跟 ID 的值确实一样,物理上的分布的值和 id 分布是一样的

id 等于一的放在第一条记录,等于二放在第二条记录。correlation 等于一表示它完全相近,如果反着来,它的顺序会完全相。如果把它 truncate 掉,它的记录反着来,insert into test1 select generate_series 〈100000,1,-1〉,现在反着来,看一下表的统计信息,analyze test1,可以看到它的顺序是完全反着的。

image.png

跟存储数据是反着的。

most_common_elems 和 most_common_elem_freqs如果存储的是数组类型,就会有 most_common_elem_freqs 这个字段,这个字段对应的数组全部打散之后就会有 most_common_elems,对应的百分比是多少

elem_count_histogram 也是跟数组有关系。

5、全表扫描

Digoal=#explain seloct * from f;

QUERY PLAN

Scq Scan on f(cost-0.00.12999.00 rows=640000 width-49)

(1row)

Cost是怎么得来的?全表扫描的成本计算只需要用到pg_class. digoal=# select relpages,reltuples from pg_class where relname='f';

relpages | relruples 57

6599| 640000

(1 row)

全表扫描成本怎样计算已经讲过了,是连续扫描的代价因子乘以有多少个数据块,再加上 cpu_tuple_cost 乘以 CPU的行数。

digoal=# show seq_page_cost;

seq_page_cost

1

row)

digoal=# show cpu_tuple_cost;

cpu_tuple_cost

0.01

(1 row)

COST值:

digoal=# select 6599*1+640000*0.01;

?column?

12999.00

(1 row)

 

五、EXPLAIN 行数评估

1、从柱状图评估行数的例子,就是评估出来的行数是怎样得来的?举个例子,explain select * from test1 where id<1000,

image.png

1012行怎样来的?

EXPLAIN SELECT*FROM tenk1 WHEREunique1<1000;

QUERYPLAN

Bitmap Heap Scan on tenk1(cost=24.06.394.64 rows=1007 width=244)

Recheck Cond:(unique1<1000)

->Bitmap Index Scan on tenk1_unique1 (cost=0.00..23.80 rows=1007 width=0)

Index Cond:(uniquel1<1000)

8.3以及以前版本default_statistics_target默认是10,也就是10个bucket

SELECT histogram_bounds FROM pg_stats

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

histogram_bounds

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

上面例子是1007行,我们举的例子是1012行。总的行数是十万行,select * from pg_class where oid=‘test1’::regclass,来自于下图

image.png

它有100个 bucket,小于1000,第一个 bucket 已经完全拥有了,第二个bucket 只占了其中的一部分。

2、这个例子的行选择性如下

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

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

=0.100697

最终得到的行数是:

rows=rel_cardinality* selectivity

=10000*0.100697

=1007 (rounding off)

这里rel_cardinality=pg_class.reltuples.

1表示一个 bucket,1000-bucket[2].min 改成 2041 减去 min,除以第二个 bucket 总共的范围段,select (1+(1000-987.0)/(2041-987.0)),这个bucket 就算出来了,再除以总共 bucket(100个),结果是0.01.

这个结果再乘以有多少个记录,有十万条记录,结果是1012

就是下面得出的行数1012,这是一种评估算法。

image.png

3、从MCV(most common valucs)评估行数的例子

EXPLAIN SELECT* FROM tenkI WHERE stringul='CRAAAA';

QUERY PLAN

Scq Scan on tenk1(cost=0.00483.00 rows=30 width=244) Filter:(stringul='CRAAAA'::name)

SELECT null frac,n distinct,mostcommon_valsmost_common

_freqs FROM pg_stats

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

Null_frac   | 0

n_distinct   | 676

most_common_vals |(EJAAAA,BBAAAA,CRAAAA,FCAAAA,FEAAAA,GSAAAA,JOAAAA,MCAAAA,NAAAAA,WGAAAA)

most common freqs | {0.00333333,0.003,0.003,0.003,0,003,

0.003,0.003,0.003,0.003,0.003)

还有一种评估算法是从 most common valucs 里面评估,假如这个值正好落在 most common valucs,insert into test1 select 1 from

generate_series<1,10000>,插入十万条1到这个表中,analyze test1,1里面有十万条,如果改成 id=1,有多少数据能够评估出来?

image.png

可以看到 most_common_vals 就有了,most_common_freqs 的占比是50%多,然后乘以行数。select * from pg_class where oid=’test1’::regclass,现在的行数变成了二十万。

200000*0.502167 得到的就是行数就是评估出来的行数。

4、从 MCV(most common values) 和 distinct 值个数评估行数的例子

EXPLAIN SELECT*FROM tenk WHERE stringul='xxx';

QUERY PLAN

Scq Scan on tenk1(cost=0.00483.00 rows=15 width=244) Filter:(stringul='xxx'::name)

1减去所有MCV的占比,再乘以distinct值的个数减去MCV的个数 selectivity=(1-sum(mvf))(num_distinct-num_mcv)

=(1-(0.00333333+0.003+0.003+0.003+0.003+0.003+

0.003+0.003+0.003+0.003)/(676-10)

=0.0014559

rows=10000*0.0014559

= 15 (rounding off)

条件改一下,不是 where id=1 了,而是 where id=2explain select * from test1 where id=2,

image.png

4行是用 (1-sum(mvf))(num_distinct-num_mcv) 公式算出来的。除了 most_common_vals 的占比之外记录的占比,select <1-0.502167> 是剩余记录的占比,除以 num_distinct,num_distinct 是一个负数。

如果它大于零是 number of distinct values in the column;如果小于零是一个占比,占了12.96%。如果是负数选择性相当于是distinct 值的比列,distinct 值相当于乘以20万,因为有20万条记录然后减去 most_common_vals 的个数,id=1 的只有一个,1减去 most_common_vals 的频率(0.501867),再除以 25919,就得到了等于单个值的选择列。

select 200000*0.00019218835603225433080,得到3.8,约等于4。

5、

image.png

还有例子是小于一个值的,同时还有 most common valuse,这种选择算法要用到 most common valuse 以及其他的一些东西。histogram_bounds是一个柱状图,在柱状图里的占比相当于要刨去 most common valuse,也就是下面这些 bucket 总共的占比相当于1减去 most common valuse 占比的总和,

这些 bucket 只占了49.82%,在计算的时候要减去那些值,最后得到的选择性。假如现在的值大于一万,

image.png

rows 行就相当于要刨去0.501867选择性,从大于一万的数总共有多少个 bucket。为了方便计算大于97866,大于97866相当于在里面占有两个 bucket,select (1-0.501867)*2/100,得到它的选择性如图

image.png

得到这个选择性之后再乘以20万,就得到了1993这个行数(四舍五入)。

6、多个列查询条件的选择性相乘评估例子

EXPLAIN SELECT*FROM tenk1 WHERE unique1<1000 AND stringul='xxx';

QUERY PLAN

Bitmap Hcap Scan on tenk1(cost=23.80..396.91 rows=1 width=244)

Recheck Cond:(unique1<1000)

Filter:(stringul='xxx'::name)

->Bitmap Index Scan on tenk1_unique1 (cost=0.00..23.80 rows=1007 width=0)

Index Cond:(unique1<1000)

多列的选择性相乘得到最终的选择性

selectivity=selectivity(unique1<1000)* selectivity(stringul='xxx')

=0100697*0.0014559

=0.0001466

rows =10000*0.0001466

=1 (rounding off)

对于有多种条件的,又有等于又有小于,它的评估是 unique1<1000 字段的选择性乘以 stringul='xxx' 字段的选择性。

 

六、EXPLAIN 成本计算-索引扫描

1、索引扫描时,和全表扫描不同,扫描 PAGE 的开销是pages*random_page_cost。

另外,索引扫描一般都涉及操作符,例如大于、小于,等于。所以在计算索引扫描成本的时候,和计算全表扫描会更加复杂,这些操作符对应的函数的 COST 乘以cpu_operator_cost 就得到这个操作符的代价因子,乘以实际操作的行数就得到 CPU 操作符开销,Rows Explain 中可能无输出。

2、索引的CPU开销则是实际扫描的索引条目数乘以cpu index_tuplecostRows Explain中无输出。最后的一个开销是实际返回或丢给上层的TUPLE带来的 CPU开销cpu_tuple_cost*实际扫描的行数Rows Explain中有输出。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
6月前
|
SQL 关系型数据库 分布式数据库
在PolarDB中,行数评估是通过对表的统计数据、基数估计以及算子代价模型来进行估算的。
【2月更文挑战第14天】在PolarDB中,行数评估是通过对表的统计数据、基数估计以及算子代价模型来进行估算的。
140 1
|
SQL 索引 OceanBase
OBCP第四章 SQL调优-局部索引与全局索引
OBCP第四章 SQL调优-局部索引与全局索引
158 0
|
16天前
|
SQL 关系型数据库 MySQL
惊呆:where 1=1 可能严重影响性能,差了10多倍,快去排查你的 sql
老架构师尼恩在读者交流群中分享了关于MySQL中“where 1=1”条件的性能影响及其解决方案。该条件在动态SQL中常用,但可能在无真实条件时导致全表扫描,严重影响性能。尼恩建议通过其他条件或SQL子句命中索引,或使用MyBatis的`&lt;where&gt;`标签来避免性能问题。他还提供了详细的执行计划分析和优化建议,帮助大家在面试中展示深厚的技术功底,赢得面试官的青睐。更多内容可参考《尼恩Java面试宝典PDF》。
|
6月前
|
缓存 关系型数据库 MySQL
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
1031 0
|
6月前
|
缓存 关系型数据库 MySQL
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
282 0
|
4月前
|
SQL 运维 监控
MSSQL性能调优深度解析:索引精细调整、SQL查询优化与并发控制策略
在Microsoft SQL Server(MSSQL)的运维实践中,性能调优是确保数据库高效、稳定运行的核心任务
|
4月前
|
SQL 监控 数据库
MSSQL性能调优深度探索:索引精细调整、SQL重写优化与智能并发控制
在Microsoft SQL Server(MSSQL)的日常管理和维护中,性能调优是一项至关重要的任务
|
4月前
|
SQL 存储 监控
MSSQL性能调优深度解析:索引策略优化、SQL语句精炼与并发管理技巧
在Microsoft SQL Server(MSSQL)的性能调优领域,索引策略的优化、SQL语句的精炼以及高效的并发管理技巧是提升数据库性能不可或缺的三大方面
|
SQL 算法 Cloud Native
数据库内核那些事|细说PolarDB优化器查询变换 - join消除篇
数据库的查询优化器是整个系统的"大脑",一条SQL语句执行是否高效在不同的优化决策下可能会产生几个数量级的性能差异,因此优化器也是数据库系统中最为核心的组件和竞争力之一。阿里云瑶池旗下的云原生数据库PolarDB MySQL版作为领先的云原生数据库,希望能够应对广泛用户场景、承接各类用户负载,助力企业数据业务持续在线、数据价值不断放大,因此对优化器能力的打磨是必须要做的工作之一。 本系列将从PolarDB for MySQL的查询变换能力开始,介绍我们在这个优化器方向上逐步积累的一些工作。
11413 0
|
SQL 移动开发 关系型数据库
PostgreSQL 执行计划,成本公式解说,代价因子校准,自动跟踪SQL执行计划(三)|学习笔记
快速学习PostgreSQL 执行计划,成本公式解说,代价因子校准,自动跟踪SQL执行计划(三)
PostgreSQL 执行计划,成本公式解说,代价因子校准,自动跟踪SQL执行计划(三)|学习笔记