PostgreSQL 快速返回表上某列的唯一值(枚举值) - pg_stats.most_common_vals

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 标签PostgreSQL , 统计信息 , 唯一值 , 枚举值背景PostgreSQL的列统计信息中包含一项高频词,同时包含一项唯一值个数。pg_stats.n_distinct pg_stats.most_common_vals 同时PostgreSQL允许用户自定义统计信息柱状图BUCKET的个数。

标签

PostgreSQL , 统计信息 , 唯一值 , 枚举值


背景

PostgreSQL的列统计信息中包含一项高频词,同时包含一项唯一值个数。

pg_stats.n_distinct  
  
pg_stats.most_common_vals  

同时PostgreSQL允许用户自定义统计信息柱状图BUCKET的个数。

alter table     ALTER [ COLUMN ] column_name SET STATISTICS integer  
  
  

默认柱状图BUCKET个数为100

postgres=# show default_statistics_target ;  
 default_statistics_target   
---------------------------  
 100  
(1 row)  

当唯一值的个数小于柱状图的BUCKET个数时,从高频词(pg_stats.most_common_vals)得到的实际上就是该列的唯一值的内容。

例子

使用一个函数,加上以上判断逻辑,用来直接获取某个表,某个列的唯一值的内容。

create or replace function get_distinct_value(  
  name,   -- schema  
  name,   -- table  
  name    -- column  
) returns text as $$  
declare  
  v int;  
  res text;  
begin  
  select   
    case attstattarget   
      when -1 then current_setting('default_statistics_target')::int   -- 默认bucket  
      else attstattarget   -- 自定义bucket  
    end into v   
  from pg_attribute where attrelid=($1||'.'||$2)::regclass and attname=$3 ;  
    
  select (most_common_vals)::text into res -- 高频词  
    from pg_stats where not inherited and schemaname = $1 and tablename = $2 and attname = $3 and n_distinct >=1 and n_distinct <= v;  
  return res;  
end;  
$$ language plpgsql strict;  

1、创建测试表,写入测试数据

postgres=# create table tbl(id int,c1 int,c2 int);  
CREATE TABLE  
postgres=# insert into tbl select id, random()*100, random()*200 from generate_series(1,10000000) t(id);  
INSERT 0 10000000  

2、分析表

postgres=# analyze tbl;  
ANALYZE  

3、通过以上函数,获取c1列的唯一值内容。

postgres=# select * from get_distinct_value('public','tbl','c1') ;  
 get_distinct_value   
--------------------  
   
(1 row)  

返回空,因为bucket个数小于n_distinct,所以得到的唯一值实际上是不准确的。因此返回了空,与逻辑相符。

4、修改C1,C2列的BUCKET为300,大于实际的唯一值个数

postgres=# alter table tbl alter COLUMN c1 set statistics 300;  
ALTER TABLE  
postgres=# alter table tbl alter COLUMN c2 set statistics 300;  
ALTER TABLE  
  
重新分析表  
postgres=# analyze tbl;  
ANALYZE  

5、通过以上函数,获取c1, c2列的唯一值内容。 得到了正确的结果

postgres=# select * from get_distinct_value('public','tbl','c1') ;  
                                                                                                                                           get_distinct_value                                                                                  
                                                              
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
------------------------------------------------------------  
 {56,83,61,67,37,8,53,66,17,44,29,54,9,15,85,49,80,96,58,22,47,68,62,30,77,34,64,23,39,11,5,24,42,7,3,32,57,73,88,40,93,13,91,86,51,89,81,43,71,35,45,48,84,16,87,50,27,99,4,25,38,14,41,72,78,95,74,76,18,94,28,90,2,12,79,21,70,36,52,75,31  
,33,55,60,92,6,63,69,98,46,97,19,59,26,20,10,65,1,82,0,100}  
(1 row)  
  
postgres=# select * from get_distinct_value('public','tbl','c2') ;  
                                                                                                                                                                                                                                               
                                                                                                      get_distinct_value                                                                                                                       
                                                                                                                                                                                                                                 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
 {75,132,83,91,82,69,4,74,195,35,157,124,178,13,61,134,70,153,31,190,3,150,84,135,140,50,114,152,193,119,147,116,143,199,11,45,68,94,183,5,93,51,130,32,98,46,118,47,52,79,146,6,39,101,154,162,191,66,148,165,187,21,67,72,103,54,73,122,106  
,127,131,137,168,169,179,96,115,177,186,64,121,14,29,37,30,78,17,80,117,120,133,144,159,7,26,38,113,172,141,158,89,155,164,15,63,125,184,108,12,189,56,139,20,59,43,104,126,48,65,163,166,19,28,77,180,194,95,99,198,176,16,33,40,110,160,197  
,49,100,167,2,8,18,55,156,188,36,53,88,90,142,185,27,42,85,1,109,25,62,57,107,123,76,112,86,10,71,128,149,175,24,34,92,173,181,60,97,136,151,41,58,111,161,192,9,81,87,105,182,23,129,138,145,171,44,174,196,22,170,102,200,0}  
(1 row)  
  
  
postgres=# select * from unnest(get_distinct_value('public','tbl','c2')::int[]) ;  
 unnest   
--------  
     75  
    132  
     83  
     91  
     82  
     69  
      4  
     74  
... ...  
  
(201 rows)  

小结

1、由于统计信息并不是实时更新的,所以使用本文提到的方法,并不一定能得到实时的准确结果。但是可以在执行前ANALYZE一下,那么得到的结果就非常准确。

2、当时有本文提到的方法返回的结果为NULL时,再使用select x from tbl group by x;来返回唯一值。

统计信息中有很多有趣的内容,比如还可以用来

1、评估高频词,例如我们的表里面存储了APP的下周记录,我们通过高频词可以评估出热门的APP。

2、通过explain还可以用来评估SQL的返回记录数。用于分页评估。

《妙用explain Plan Rows快速估算行 - 分页数估算》

参考

《PostgreSQL 11 preview - 表达式索引柱状图buckets\STATISTICS\default_statistics_target可设置》

《PostgreSQL 统计信息pg_statistic格式及导入导出dump_stat - 兼容Oracle》

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
Oracle 关系型数据库
查询Oracle字段列的最大值并查询多列数据的实现方法
查询Oracle字段列的最大值并查询多列数据的实现方法
2224 0
|
数据库 索引 Python
SQLAlchemy列参数的使用和query函数的使用
SQLAlchemy列参数的使用和query函数的使用
|
SQL 数据采集 关系型数据库
SQL中对数据字段null值的处理
SQL中对数据字段null值的处理
SQL中对数据字段null值的处理
|
关系型数据库 MySQL 索引
Mysql 唯一索引的字段值 允许多个NULL值存在吗
Mysql 唯一索引的字段值 允许多个NULL值存在吗
661 0
Mysql 唯一索引的字段值 允许多个NULL值存在吗
|
关系型数据库 定位技术 数据库
【DB吐槽大会】第50期 - PG GiST距离排序操作符和过滤无法同时使用索引
大家好,这里是DB吐槽大会,第50期 - PG GiST距离排序操作符和过滤无法同时使用索引
|
弹性计算 关系型数据库 测试技术
PostgreSQL 分区表如何支持多列唯一约束 - 枚举、hash哈希 分区, 多列唯一, insert into on conflict, update, upsert, merge insert
标签 PostgreSQL , 分区表 , native partition , 唯一 , 非分区键唯一 , 组合唯一 , insert into on conflict , upsert , merge insert 背景 PG 11开始支持HASH分区,10的分区如果要支持hash分区,可以通过枚举绕道实现。 《PostgreSQL 9.x, 10, 11 hash分区表 用法举例
3117 0
|
SQL Go 数据库
MSSQL sql server 2005/2008 row_number()函数应用之–删除表中重复记录,只保留一条不重复数据
原文:MSSQL sql server 2005/2008 row_number()函数应用之–删除表中重复记录,只保留一条不重复数据 转自:http://www.maomao365.com/?p=4942 下文主要讲述:重复数据只获取一条的方法 row_number函数在数据库中的功能是为每一...
1165 0
|
SQL 数据格式 XML
SQL Server Update 所有表的某一列(列名相同,类型相同)数值
DECLARE @sql VARCHAR(5000); WITH T AS (SELECT SchemaName = c.TABLE_SCHEMA, TableName = c.
1738 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版
  • 下一篇
    无影云桌面