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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介: 标签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字段列的最大值并查询多列数据的实现方法
2103 0
|
存储 关系型数据库 PostgreSQL
|
10月前
|
关系型数据库 MySQL
mysql统计数据表中同一字段不同状态的COUNT()语句
mysql统计数据表中同一字段不同状态的COUNT()语句
67 0
|
4天前
|
SQL 关系型数据库 MySQL
SQL编程【MySQL 01】拆分列字段为行并根据类型翻译字段 > 1305 - FUNCTION x.help_topic_id does not exist 报错问题
SQL编程【MySQL 01】拆分列字段为行并根据类型翻译字段 > 1305 - FUNCTION x.help_topic_id does not exist 报错问题
39 0
|
SQL Oracle 关系型数据库
oracle中使用sql查询时字段为空 赋值默认值 ( 通过 nvl( )函数 )
oracle中使用sql查询时字段为空 赋值默认值 ( 通过 nvl( )函数 )
473 0
oracle中使用sql查询时字段为空 赋值默认值 ( 通过 nvl( )函数 )
|
关系型数据库 MySQL 索引
Mysql 唯一索引的字段值 允许多个NULL值存在吗
Mysql 唯一索引的字段值 允许多个NULL值存在吗
466 0
Mysql 唯一索引的字段值 允许多个NULL值存在吗
|
关系型数据库 MySQL 数据库
MySQL - GROUP BY 隐式排序
MySQL - GROUP BY 隐式排序
286 0
MySQL - GROUP BY 隐式排序
|
关系型数据库 MySQL Java
mysql字段的细节(查询自定义的字段[意义:行列转置];UNION ALL;case-when)
mysql字段的细节(查询自定义的字段[意义:行列转置];UNION ALL;case-when)
190 0
mysql字段的细节(查询自定义的字段[意义:行列转置];UNION ALL;case-when)
|
弹性计算 关系型数据库 测试技术
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分区表 用法举例
2927 0
|
SQL 索引 关系型数据库
MySQL字段类型转换引发的索引失效
概述 最近发现一个有趣的SQL优化场景,分享一下 测试数据 表结构 CREATE TABLE `news_webpage` ( `id` int(11) NOT NULL AUTO_INCREMENT, `t1` varchar(100) DEFAULT NULL, `t2` text.
2042 0

相关产品

  • 云原生数据库 PolarDB