热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PostgreSQL10黑科技自定义统计信息

digoal德哥专栏PostgreSQL10黑

作者

digoal


日期

2017-09-02


标签

PostgreSQL , 多列统计信息 , 多列唯一值 , 多列依赖度 , 任意维度TOP N




背景

PostgreSQL和Oracle一样,优化器是基于成本的估算。

成本估算中很重要的一个环节是估计每个执行节点返回的记录数。

例如两张表JOIN的时候,如果走HASH JOIN那么需要选择记录数少的那个作为哈希表。

又比如求多个字段的group by,评估返回多少条记录给上层节点。

对于基于单列统计的的柱状图,估算单个字段条件的选择性是很准确的,而估算多个字段时,PostgreSQL默认使用独立属性,直接以多个字段选择性相乘的方法计算多个字段条件的选择性。不是很准确。

PostgreSQL 10引入了一个黑科技功能,允许用户自定义多个字段的统计信息,目前支持多列相关性和多列唯一值两种统计。

由于多列统计涉及到许多组合(N阶乘种组合),因此默认不会对所有字段进行任意组合的统计,用户可以根据实际的业务需求,对需要and查询,组合group by的字段(例如 where a xx and b xx, group by a,b)。创建对应的自定义统计信息。


例子讲解

1、建表,11个字段。

postgres=# create table tbl(id int, c1 int, c2 text, c3 int, c4 int, c5 int, c6 int, c7 int, c8 int, c9 int, c10 int);
CREATE TABLE

2、写入测试数据,1000万条。

postgres=# insert into tbl select
postgres-# id,
postgres-# random()*100, substring(md5(random()::text), 1, 4), random()*900, random()*10000, random()*10000000,
postgres-# random()*100000, random()*100, random()*200000, random()*40000, random()*90000
postgres-# from generate_series(1,10000000) t(id);
INSERT 0 10000000

3、分析表

postgres=# analyze tbl;
ANALYZE

得到reltuples为1e+07,后面要用于计算。

postgres=# select reltuples from pg_class where relname='tbl';
-[ RECORD 1 ]----
reltuples | 1e+07

4、SQL举例

4.1 单个字段条件

```

postgres=# explain (analyze) select * from tbl where c1=1;

QUERY PLAN



Seq Scan on tbl (cost=0.00..218458.08 rows=93865 abc';

QUERY PLAN



Seq Scan on tbl (cost=0.00..218458.08 rows=148 abc'::text)

Rows Removed by Filter: 10000000

Planning time: 0.080 ms

Execution time: 874.505 ms

(5 rows)

```

可以推算得到c2='abc'的选择性为: 148/1e+07 。

4.2 多个字段条件

```

postgres=# explain (analyze) select * from tbl where c1=1 and c2='abc';

QUERY PLAN



Seq Scan on tbl (cost=0.00..243458.09 rows=1 abc'::text))

Rows Removed by Filter: 10000000

Planning time: 0.116 ms

Execution time: 802.374 ms

(5 rows)

```

rows=1是怎么得来的呢,在没有自定义统计信息时,是这么算的,算这两个条件完全不相干,所以选择性直接相乘。

(93865/1e+07) * (148/1e+07) * 1e+07 = 1.389202 ~= 1

4.3 单个字段条件求唯一值

```

postgres=# explain (analyze) select c1,count(*) from tbl group by c1;

QUERY PLAN



HashAggregate (cost=243458.09..243459.10 rows=101 101

4.4 多个字段条件求唯一值

```

postgres=# explain (analyze) select c1,c2,count(*) from tbl group by c1,c2;

QUERY PLAN



GroupAggregate (cost=1561215.43..1671215.50 rows=1000001 s1';
-[ RECORD 1 ]---+--------------------------------------------------------------------------------------------------------------
stxrelid | 16384 -- 表
stxname | s1
stxnamespace | 2200
stxowner | 10
stxkeys | 2 3 4 -- 表示第2,3,4列创建自定义统计信息。
stxkind | {d,f} -- 统计 字段之间的依赖度(相关性)、唯一值个数。
stxndistinct | {"2, 3": 3747653, "2, 4": 87662, "3, 4": 9001205, "2, 3, 4": 10000006} -- 组合唯一值个数
stxdependencies | {"3 => 2": 0.642100, "3 => 4": 0.639567, "2, 3 => 4": 0.995000, "2, 4 => 3": 0.712033, "3, 4 => 2": 0.999667}
-- 字段之间的依赖性,当使用多个字段AND条件时,用于代替多个孤立条件的选择性相乘。选择性乘以依赖度,选出最后计算结果最低的,作为最终选择性。

stxndistinct,很好理解,就是字段组合后的唯一值个数。

stxdependencies,当一个字段确定后,另一个字段是唯一值的比例有多少?例如a=1, b={1,2,3,4,5,....}; a=2,b=1,这里只有后面这条算b依赖a。 依赖条数除以总数即a => b的依赖值。可以用于评估两个字段都是等值条件时的选择性。生成stxdependencies的算法很简单,a => b 等于 count(distinct a)/count(distinct a,b);b=>a 等于 count(distinct b)/count(distinct a,b);

```

postgres=# \d t

Table "public.t"

Column | Type | Collation | Nullable | Default

--------+---------+-----------+----------+---------

c1 | integer | | |

c2 | integer | | |

Statistics objects:

"public"."s1" (ndistinct, dependencies) ON c1, c2 FROM t

postgres=# select * from pg_statistic_ext where stxname='s2';

stxrelid | stxname | stxnamespace | stxowner | stxkeys | stxkind | stxndistinct | stxdependencies

----------+---------+--------------+----------+---------+---------+------------------+------------------------------------------

16394 | s2 | 2200 | 10 | 1 2 | {d,f} | {"1, 2": 105358} | {"1 => 2": 0.083733, "2 => 1": 0.916200}

(1 row)

postgres=# select count(distinct c1) from t;

count



10000

(1 row)

postgres=# select count(distinct c2) from t;

count



100001

(1 row)

postgres=# select count(distinct (c1,c2)) from t;

s count



109999

(1 row)

postgres=# select 10000/109999.0;

?column?



0.09090991736288511714

(1 row)

postgres=# select 100001/109999.0;

?column?



0.90910826462058745989

(1 row)

postgres=# select 0.083733+0.916200;

?column?



0.999933

(1 row)

```

评估例子

a = ? and b = ? 的选择性
=
min( "选择性(a) * (a=>b)" , "选择性(b) * (b=>a)" )

8、SQL举例

8.1 多个字段条件

```

postgres=# explain (analyze) select * from tbl where c1=1 and c2='abc';

QUERY PLAN



Seq Scan on tbl (cost=0.00..243458.09 rows=96 abc'::text))

Rows Removed by Filter: 10000000

Planning time: 0.098 ms

Execution time: 802.203 ms

(5 rows)

```

创建了多字段统计信息后,这两个条件在统计信息之列,所以可以用他们的依赖度来算组合AND条件的选择性。

算法:选择性最低的条件的选择性 * 与另一个字段的依赖度,得到组合选择性。

0.642100 * (148/1e+07) * 1e+07 = 95.0308 (这里反推的选择性有一点失真,大概原理就是这样)

8.2 多个字段条件求唯一值

```

postgres=# explain (analyze) select c1,c2,count(*) from tbl group by c1,c2;

QUERY PLAN



GroupAggregate (cost=1561215.43..1698692.02 rows=3747653 2, 3": 3747653

9、如何利用自定义统计信息统计多个字段 唯一值、多列依赖性。

9.1 PostgreSQL已有了单列唯一值的统计,我们可以通过pg_stats.n_distinct以及pg_class.reltuples查询到。

通过create statistic,数据库会自动收集多列值的统计信息,我们查询pg_statistic_ext.stxndistinct,可以得到多列唯一值的估计值。

9.2 多列依赖性指的是列与列之间值的依赖强度,是一个小于等于1的系数。1表示强依赖,


小结

1、PostgreSQL 10支持自定义多列统计信息,目前支持 多列组合唯一值、列与列的相关性。

2、多列唯一值可用于评估group by, count(distinct)等。

3、列与列相关性可用于估算多个列AND条件的选择性。算法

a = ? and b = ? 的选择性
=
min( "选择性(a) * (a=>b)" , "选择性(b) * (b=>a)" )

4、由于多列统计信息的组合很多,因此数据库默认只统计单列的柱状图。当用户意识到某些列会作为组合查询列时,再创建自定义多列统计信息即可。


参考

https://www.postgresql.org/docs/10/static/multivariate-statistics-examples.html

https://www.postgresql.org/docs/10/static/sql-createstatistics.html

https://www.postgresql.org/docs/10/static/planner-stats.html#planner-stats-extended


PostgreSQL 许愿链接

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.


9.9元购买3个月阿里云RDS PostgreSQL实例


PostgreSQL 解决方案集合


德哥 / digoal's github - 公益是一辈子的事.

digoal's wechat


推荐阅读
  • 花瓣|目标值_Compose 动画边学边做夏日彩虹
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Compose动画边学边做-夏日彩虹相关的知识,希望对你有一定的参考价值。引言Comp ... [详细]
  • HashMap的扩容知识详解
    本文详细介绍了HashMap的扩容知识,包括扩容的概述、扩容条件以及1.7版本中的扩容方法。通过学习本文,读者可以全面了解HashMap的扩容机制,提升对HashMap的理解和应用能力。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • Python使用Pillow包生成验证码图片的方法
    本文介绍了使用Python中的Pillow包生成验证码图片的方法。通过随机生成数字和符号,并添加干扰象素,生成一幅验证码图片。需要配置好Python环境,并安装Pillow库。代码实现包括导入Pillow包和随机模块,定义随机生成字母、数字和字体颜色的函数。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • #define_CRT_SECURE_NO_WARNINGS#includelist.h#includevoidSListInit(PNode*pHead ... [详细]
author-avatar
dushearer304
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有