【PostgreSQL内核学习(十六)—— (pg_statistic 表)】

声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。
本文主要参考了《PostgresSQL数据库内核分析》一书,OpenGauss1.1.0 的开源代码和《OpenGauss数据库源码解析》一书以及OpenGauss社区学习文档

概述

  之前我们在文章【 OpenGauss源码学习 —— 列存储(analyze)(一)】中使用 SQL 语句:SELECT * FROM pg_statistic WHERE starelid = 'sales'::regclass;观察到了数据库表所收集到的统计信息。其中,pg_statisticPostgreSQL 中的系统表,用于存储关于表列的统计信息。这些统计信息包括列中的值分布唯一值的数量空值的数量等等。本文我们则来详细的学习一下 pg_statistic 表。

pg_statistic 表

  pg_statistic 表的主要作用是查询优化器提供关于表列数据分布的信息,以便它可以生成更好的执行计划。具体来说,pg_statistic 表中的每一行都对应于一个表列的统计信息。这些统计信息对于 PostgreSQL 查询优化器来说非常重要,因为它可以帮助优化器决定如何访问表数据以获得最佳性能。例如,通过了解列中不同值的数量和数据分布,优化器可以选择合适的索引、连接顺序和连接方法,以及其他执行计划细节,从而提高查询的效率。
  接下来,我们依旧按照【 OpenGauss源码学习 —— 列存储(analyze)(一)】中的案例进行分析。案例如下:

1. 创建列存储表,执行以下 SQL 语句

CREATE TABLE sales (
    sale_id SERIAL PRIMARY KEY,
    product_id INT,
    sale_date DATE,
    quantity INT,
    amount DECIMAL
) WITH (ORIENTATION = COLUMN);

postgres=# select * from sales;
 sale_id | product_id | sale_date | quantity | amount
---------+------------+-----------+----------+--------
(0 rows)

postgres=# \d+ sales
                                                             Table "public.sales"
   Column   |              Type              |                        Modifiers                        | Storage | Stats target | Description
------------+--------------------------------+---------------------------------------------------------+---------+--------------+-------------
 sale_id    | integer                        | not null default nextval('sales_sale_id_seq'::regclass) | plain   |              |
 product_id | integer                        |                                                         | plain   |              |
 sale_date  | timestamp(0) without time zone |                                                         | plain   |              |
 quantity   | integer                        |                                                         | plain   |              |
 amount     | numeric                        |                                                         | main    |              |
Has OIDs: no
Options: orientation=column, compression=low

2. 插入一些示例数据到列存储表中

INSERT INTO sales (product_id, sale_date, quantity, amount)
VALUES
    (101, '2023-08-01', 10, 100.00),
    (102, '2023-08-02', 5, 50.00),
    (101, '2023-08-03', 8, 80.00);

postgres=# select * from sales;
 sale_id | product_id |      sale_date      | quantity | amount
---------+------------+---------------------+----------+--------
       1 |        101 | 2023-08-01 00:00:00 |       10 | 100.00
       2 |        102 | 2023-08-02 00:00:00 |        5 |  50.00
       3 |        101 | 2023-08-03 00:00:00 |        8 |  80.00
(3 rows)

3. 执行 ANALYZE 进行统计信息收集

postgres=# ANALYZE sales;
ANALYZE

4. 查看统计信息和优化计划

查看表的统计信息,如不同列的值分布等:
postgres=# SELECT * FROM pg_statistic WHERE starelid = 'sales'::regclass::oid;
 starelid | starelkind | staattnum | stainherit | stanullfrac | stawidth | stadistinct | stakind1 | stakind2 | stakind3 | stakind4 | stakind5 | staop1 | staop2 |
 staop3 | staop4 | staop5 | stanumbers1 | stanumbers2 | stanumbers3 | stanumbers4 | stanumbers5 |                             stavalues1
     | stavalues2 | stavalues3 | stavalues4 | stavalues5 | stadndistinct | staextinfo
----------+------------+-----------+------------+-------------+----------+-------------+----------+----------+----------+----------+----------+--------+--------+
--------+--------+--------+-------------+-------------+-------------+-------------+-------------+----------------------------------------------------------------
-----+------------+------------+------------+------------+---------------+------------
    40980 | c          |         1 | f          |           0 |        4 |          -1 |        2 |        3 |        0 |        0 |        0 |     97 |     97 |
      0 |      0 |      0 |             | {1}         |             |             |             | {1,2,3}
     |            |            |            |            |             0 |
    40980 | c          |         2 | f          |           0 |        4 |    -.666667 |        1 |        3 |        0 |        0 |        0 |     96 |     97 |
      0 |      0 |      0 | {.666667}   | {.5}        |             |             |             | {101}
     |            |            |            |            |             0 |
    40980 | c          |         3 | f          |           0 |        8 |          -1 |        2 |        3 |        0 |        0 |        0 |   2062 |   2062 |
      0 |      0 |      0 |             | {1}         |             |             |             | {"2023-08-01 00:00:00","2023-08-02 00:00:00","2023-08-03 00:00:
00"} |            |            |            |            |             0 |
    40980 | c          |         4 | f          |           0 |        4 |          -1 |        2 |        3 |        0 |        0 |        0 |     97 |     97 |
      0 |      0 |      0 |             | {-.5}       |             |             |             | {5,8,10}
     |            |            |            |            |             0 |
    40980 | c          |         5 | f          |           0 |       11 |          -1 |        2 |        3 |        0 |        0 |        0 |   1754 |   1754 |
      0 |      0 |      0 |             | {-.5}       |             |             |             | {50.00,80.00,100.00}
     |            |            |            |            |             0 |
(5 rows)


查看查询的优化计划:
postgres=# EXPLAIN SELECT * FROM sales WHERE product_id = 101;
                          QUERY PLAN
---------------------------------------------------------------
 Row Adapter  (cost=3.01..3.01 rows=2 width=31)
   ->  CStore Scan on sales  (cost=0.00..3.01 rows=2 width=31)
         Filter: (product_id = 101)
(3 rows)

SQL 语句解读

  首先,我们先来解读一下这句 SQL 语句:SELECT * FROM pg_statistic WHERE starelid = 'sales'::regclass;

  该语句的作用是从 PostgreSQL 系统目录中的 pg_statistic 表中检索统计信息查询的条件starelid 字段等于 ‘sales’ 表的 OID(对象标识符)。具体解释如下:

  1. SELECT *: 查询语句的开头,表示要检索 pg_statistic 表中的所有列和所有行
  2. FROM pg_statistic: 指定要查询的目标表pg_statistic,这是 PostgreSQL存储统计信息的系统表
  3. WHERE starelid = 'sales'::regclass::oid: 这是查询的过滤条件。它限制了结果集,只包括符合条件的行。具体来说:
  • starelidpg_statistic 表中的一个字段,它存储了统计信息所属的表的 OID对象标识符)。OIDPostgreSQL 中的一种唯一标识符,用于识别数据库对象
  • 'sales'::regclass::oid 是一个类型转换表达式,将表名 ‘sales’ 转换为 OID 类型。这是因为 starelid 存储的是表的 OID,而不是表名

  因此,整个查询的目的是检索出与名为 “sales”列存储表相关联的统计信息,以供数据库管理员和开发人员用于性能优化查询计划的生成。这些统计信息可以帮助数据库优化器更好地理解表中数据的分布,从而更好地选择执行查询的计划

pg_statistic 表属性解读

  pg_statistic 表中的每一列属性的含义如下:

属 性含 义
starelid统计信息相关联的表的 OID对象标识符)。
starelkind关联的对象类型,通常是 ‘r’,表示
staattnum与统计信息相关联的表的列的编号(从1开始)。
stainherit一个布尔值,指示统计信息是否继承自父表(如果是分区表的一部分)。
stanullfracNULL 值的分数比例,表示该列包含 NULL 值的比例。
stawidth列的平均宽度(以字节为单位)。
stadistinct不同的值的估计数量,表示该列的唯一值的数量估计
stakind1stakind5这些列包含有关统计信息种类的标志。它们可能包括:stakind1 = 1 表示直方图stakind2 = 1 表示直方图的 B-treestakind3 = 1 表示多重模式stakind4 = 1 表示单一模式stakind5 = 1 表示单一数据值
staop1staop5这些列包含与统计信息相关的操作符的 OID(对象标识符)。
stanumbers1stanumbers5这些列包含与统计信息相关的数值数据,通常是直方图的边界值
stavalues1stavalues5这些列包含与统计信息相关的值数据,通常是模式的集合
stadndistinct不同值的精确数量,通常在单一数据值模式的情况下使用。
staextinfo附加信息,通常包含有关统计信息的额外信息

pg_stats 视图和 pg_statistic 表的关系

  pg_stats 视图(pg_catalog.pg_stats)是基于 pg_statistic 表的一个视图,提供了对表和列的统计信息的更友好的访问方式pg_statistic 表存储了关于表和列的统计信息,如列的唯一值数量NULL 值比例直方图等。这些信息在查询优化期间用于生成最佳的查询执行计划。通常情况下,开发人员管理员不会直接查询 pg_statistic 表,而是使用更易读的 pg_stats 视图pg_stats 视图是对 pg_statistic 表封装,提供了更方便的访问方式。它以表格形式呈现统计信息,每行代表一个列的统计信息。视图中的列名内容更容易理解,因此更适合查询分析
  我们执行以下 SQL 语句:

postgres=# select * from pg_stats where tablename='sales';
 schemaname | tablename |  attname   | inherited | null_frac | avg_width | n_distinct | n_dndistinct | most_common_vals | most_common_freqs |
      histogram_bounds                           | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram
------------+-----------+------------+-----------+-----------+-----------+------------+--------------+------------------+-------------------+--------------------
-------------------------------------------------+-------------+-------------------+------------------------+----------------------
 public     | sales     | sale_id    | f         |         0 |         4 |         -1 |            0 |                  |                   | {1,2,3}
                                                 |           1 |                   |                        |
 public     | sales     | product_id | f         |         0 |         4 |   -.666667 |            0 | {101}            | {.666667}         |
                                                 |          .5 |                   |                        |
 public     | sales     | sale_date  | f         |         0 |         8 |         -1 |            0 |                  |                   | {"2023-08-01 00:00:
00","2023-08-02 00:00:00","2023-08-03 00:00:00"} |           1 |                   |                        |
 public     | sales     | quantity   | f         |         0 |         4 |         -1 |            0 |                  |                   | {5,8,10}
                                                 |         -.5 |                   |                        |
 public     | sales     | amount     | f         |         0 |        11 |         -1 |            0 |                  |                   | {50.00,80.00,100.00
}                                                |         -.5 |                   |                        |
(5 rows)
属 性含 义
schemaname模式名称,表示列所属的模式
tablename表名称,表示包含这个列的表的名称
attname列名称,表示列的名称
inherited一个布尔值,指示这个列是否是从父表继承而来的。如果是继承的列,该值为 true,否则为 false
null_fracNULL 值比例,表示该列中包含的 NULL 值的比例。
avg_width平均列宽度,表示该列的平均宽度(以字节为单位)。
n_distinct唯一值的数量估计,表示该列中唯一值的数量的估算值
n_dndistinct不重复的 NULL 值数量估计,表示该列中不同的 NULL 值的数量的估算值。
most_common_vals最常见的值,一个数组,包含了该列中出现频率最高的值
most_common_freqs最常见值的频率,一个数组,包含了最常见值的频率
histogram_bounds直方图的边界值,一个数组,包含了直方图的边界值。直方图用于估算不同值的密度
correlation相关性估计,表示该列的数据分布与其他列之间的相关性。取值范围为 -1(完全负相关)到 1(完全正相关)。
most_common_elems最常见的元素,一个数组,包含了该列中出现频率最高的元素
most_common_elem_freqs最常见元素的频率,一个数组,包含了最常见元素的频率
elem_count_histogram元素计数直方图,一个数组,包含了元素出现的频率

以上查询结果显示了名为 “sales” 的表的列统计信息每一行对应一个列。让我们一一解读这些信息:

  1. schemaname 和 tablename这两列表示列所属的模式schemaname)和tablename的名称,都指向 public” 模式下的 “sales” 表
  2. attname这是列的名称,分别为 “sale_id”、“product_id”、“sale_date”、“quantity” 和 “amount”
  3. inherited这一列显示了是否从父表继承了该列。所有这些列都没有从父表继承而来,所以值都为 “f”(假)
  4. null_frac表示列中 NULL 值的比例。在所有列中,NULL 值的比例都是 0,表示这些列没有 NULL 值。
  5. avg_width这是列的平均宽度(以字节为单位)。不同列的平均宽度各不相同,分别为 4、4、8、411 字节。
  6. n_distinct这列显示了唯一值的数量估计。其中,“sale_id”、“sale_date”“quantity”唯一值数量估计-1,表示 PostgreSQL 无法准确估算唯一值的数量。而 “product_id” 和 “amount” 的唯一值数量估计分别为 -0.666667 和 -1,也表示无法准确估算。
  7. n_dndistinct表示不同的 NULL 值的数量估计。在所有列中,这些值都是 0,表示没有不同的 NULL 值。
  8. most_common_vals 和 most_common_freqs这两列分别表示最常见的值及其频率。例如,“product_id” 列中的最常见值是 101频率0.666667。“sale_date” 列中包含了三个最常见的日期值频率均为 1
  9. histogram_bounds这一列包含直方图的边界值。例如,“sale_id” 列有一个直方图,其中包含了三个边界值1、23
  10. correlation表示列的数据分布其他列之间的相关性。这些值介于 -1(完全负相关)1(完全正相关)之间。例如,“product_id” 列的相关性为 0.5,表示它与其他列之间存在一定程度的正相关性
  11. most_common_elems 和 most_common_elem_freqs这两列表示最常见的元素及其频率。在这个示例中,这些列都没有填充值
  12. elem_count_histogram这一列包含元素计数直方图,记录了元素出现的频率。在这个示例中,这些列都没有填充值。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
pg_class是postgresql中的一个系统,用于存储数据库中的所有关系(、视图、序列、索引等)的元数据信息。pg_class的结构如下: 列名 | 数据类型 | 描述 --- | --- | --- relname | name | 关系的名称(名、视图名、序列名等) relnamespace | oid | 关系所属的命名空间(pg_namespace的oid) reltype | oid | 关系的类型(pg_type的oid) reloftype | oid | 如果关系是一个复合类型的,则为该类型的oid;否则为0 relowner | oid | 关系的所有者(pg_authid的oid) relam | oid | 关系所用的存储引擎(pg_am的oid) relfilenode | oid | 关系在磁盘上的文件节点号 reltablespace | oid | 关系所在的空间(pg_tablespace的oid) relpages | integer | 关系占用的磁盘页数 reltuples | float4 | 关系中的行数 relallvisible | integer | 用于热备的可见性信息 reltoastrelid | oid | 如果关系有TOAST,则为TOAST的oid;否则为0 relhasindex | boolean | 关系是否有索引 relisshared | boolean | 关系是否是共享的 relpersistence | "char" | 关系的持久性(p-永久,t-临时,u-未知) relkind | "char" | 关系的类型(r-普通,i-索引,S-序列,v-视图,m-物化视图,c-复合类型,t-函数,f-标量函数,p-过程) relnatts | smallint | 关系中的列数 relchecks | smallint | 关系中的CHECK约束数 relhasoids | boolean | 关系是否有OID列 relrowsecurity | boolean | 是否启用了行级别安全 relforcerowsecurity | boolean | 是否强制启用行级别安全 通过查询pg_class,可以获取数据库中所有关系的元数据信息,包括关系的名称、类型、所有者、存储引擎、占用磁盘空间、行数等等。这些信息对于进行数据库优化、监控和管理非常有用。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值