PG vs MySQL 统计信息收集的异同

统计信息的作用

对于一条SQL,数据库选择何种方式执行,需要根据统计信息进行估算,计算出代价最低的执行计划。收集统计信息主要是为了让优化器做出正确的判断,选择最佳的执行计划。

PG的统计信息收集

PG的统计信息相关表

在PostgreSQL里面,统计信息存放于pg_statistics系统表中,由于pg_statistics里面的内容人为不易阅读,因此便有了pg_stats视图。

pg_class看pages和tuples

postgres=# select relname,relpages,reltuples::bigint from pg_class where relname='test'\gx
-[ RECORD 1 ]-----
relname   | test
relpages  | 443
reltuples | 100000

pg_stat_all_tables看活元组、死元组,上次统计信息收集时间

postgres=# select * from pg_stat_all_tables where relname='test'\gx
-[ RECORD 1 ]-------+------------------------------
relid               | 16388
schemaname          | public
relname             | test
seq_scan            | 0
last_seq_scan       | 
seq_tup_read        | 0
idx_scan            | 
last_idx_scan       | 
idx_tup_fetch       | 
n_tup_ins           | 100000
n_tup_upd           | 0
n_tup_del           | 0
n_tup_hot_upd       | 0
n_tup_newpage_upd   | 0
n_live_tup          | 100000
n_dead_tup          | 0
n_mod_since_analyze | 0
n_ins_since_vacuum  | 0
last_vacuum         | 
last_autovacuum     | 2025-01-21 10:46:51.330118+08
last_analyze        | 
last_autoanalyze    | 2025-01-21 10:46:51.353753+08
vacuum_count        | 0
autovacuum_count    | 1
analyze_count       | 0
autoanalyze_count   | 1

pg_stats看列的统计信息

\d pg_stats
                     View "pg_catalog.pg_stats"
         Column         |   Type   | Collation | Nullable | Default 
------------------------+----------+-----------+----------+---------
 schemaname             | name     |           |          | 
 tablename              | name     |           |          | 
 attname                | name     |           |          | 
 inherited              | boolean  |           |          | ---是否是继承列
 null_frac              | real     |           |          | ---null空值的比率
 avg_width              | integer  |           |          | ---平均宽度,字节
 n_distinct             | real     |           |          | ---大于零就是非重复值的数量,小于零则是非重复值的个数除以行数
 most_common_vals       | anyarray |           |          | ---高频值
 most_common_freqs      | real[]   |           |          | ---高频值的频率
 histogram_bounds       | anyarray |           |          | ---直方图
 correlation            | real     |           |          | ---物理顺序和逻辑顺序的关联性
 most_common_elems      | anyarray |           |          | ---高频元素,比如数组
 most_common_elem_freqs | real[]   |           |          |  ---高频元素的频率
 elem_count_histogram   | real[]   |           |          |  ---直方图(元素)

PG自动收集统计信息

• 触发vacuum analyze–>
• 表上新增(insert,update,delte) >= autovacuum_analyze_scale_factor* reltuples(表上记录数) + autovacuum_analyze_threshold

postgres=# show autovacuum_analyze_scale_factor;
 autovacuum_analyze_scale_factor 
---------------------------------
 0.1
(1 row)

postgres=# show autovacuum_analyze_threshold;
 autovacuum_analyze_threshold 
------------------------------
 50
(1 row)

PG手动收集统计信息

手动收集统计信息的命令是analyze命令,analyze的语法格式:

analyze [verbose] [table[(column[,…])]]

verbose:显示处理的进度,以及表的一些统计信息

table:要分析的表名,如果不指定,则对整个数据库中的所有表作分析 

column:要分析的特定字段的名字默认是分析所有字段

analyze 命令 会在表上加读锁,不影响表上其它SQL并发执行,对于大表只会读取表中部分数据。

MySQL的统计信息收集

MySQL的统计信息相关表

• 收集的表的统计信息存放在mysql数据库的innodb_table_stats表中。
• 索引的统计信息存放在mysql数据库的innodb_index_stats表中。

mysql>  select * from mysql.innodb_table_stats where table_name='actor';
+---------------+------------+---------------------+--------+----------------------+--------------------------+
| database_name | table_name | last_update         | n_rows | clustered_index_size | sum_of_other_index_sizes |
+---------------+------------+---------------------+--------+----------------------+--------------------------+
| sakila        | actor      | 2025-01-21 16:06:31 |    200 |                    1 |                        1 |
+---------------+------------+---------------------+--------+----------------------+--------------------------+
1 row in set (0.00 sec)

mysql>  select * from mysql.innodb_index_stats where table_name='actor'; 
+---------------+------------+---------------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name          | last_update         | stat_name    | stat_value | sample_size | stat_description                  |
+---------------+------------+---------------------+---------------------+--------------+------------+-------------+-----------------------------------+
| sakila        | actor      | PRIMARY             | 2025-01-21 16:06:31 | n_diff_pfx01 |        200 |           1 | actor_id                          |
| sakila        | actor      | PRIMARY             | 2025-01-21 16:06:31 | n_leaf_pages |          1 |        NULL | Number of leaf pages in the index |
| sakila        | actor      | PRIMARY             | 2025-01-21 16:06:31 | size         |          1 |        NULL | Number of pages in the index      |
| sakila        | actor      | idx_actor_last_name | 2025-01-21 16:06:31 | n_diff_pfx01 |        121 |           1 | last_name                         |
| sakila        | actor      | idx_actor_last_name | 2025-01-21 16:06:31 | n_diff_pfx02 |        200 |           1 | last_name,actor_id                |
| sakila        | actor      | idx_actor_last_name | 2025-01-21 16:06:31 | n_leaf_pages |          1 |        NULL | Number of leaf pages in the index |
| sakila        | actor      | idx_actor_last_name | 2025-01-21 16:06:31 | size         |          1 |        NULL | Number of pages in the index      |
+---------------+------------+---------------------+---------------------+--------------+------------+-------------+-----------------------------------+
7 rows in set (0.00 sec)

MySQL自动收集统计信息

• innodb_stats_persistent
是否把统计信息持久化。
对应表选项STATS_PERSISTENT

• innodb_stats_auto_recalc
当一个表的数据变化超过10%时是否自动收集统计信息,两次统计信息收集之间时间间隔不能少10秒。
对应的表选项STATS_AUTO_RECALC

• innodb_stats_on_metadata:其触发条件是表的元数据发生变化,如执行 ALTER TABLE 等操作修改表结构时,会触发统计信息的自动更新。

• innodb_stats_persistent_sample_pages
统计索引时的抽样页数,这个值设置得越大,收集的统计信息越准确,但收集时消耗的资源越大。
对应的表选项STATS_SAMPLE_PAGES

mysql> show variables like 'innodb_stat%';
+--------------------------------------+-------------+
| Variable_name                        | Value       |
+--------------------------------------+-------------+
| innodb_stats_auto_recalc             | ON          |
| innodb_stats_include_delete_marked   | OFF         |
| innodb_stats_method                  | nulls_equal |
| innodb_stats_on_metadata             | OFF         |
| innodb_stats_persistent              | ON          |
| innodb_stats_persistent_sample_pages | 20          |
| innodb_stats_transient_sample_pages  | 8           |
| innodb_status_output                 | OFF         |
| innodb_status_output_locks           | OFF         |
+--------------------------------------+-------------+
9 rows in set (0.00 sec)

对应的表选项可以这样设置
alter table actor stats_auto_recalc=0;

MySQL手动收集统计信息

analyze local table actor,rental;

analyze table 加MDL读锁,不影响DML的并行操作。

PG vs MySQL

在自动收集统计信息的方法上,PG比MySQL更加灵活,例如在表统计信息更新触发条件上, PG可以通过调整autovacuum_analyze_scale_factor的大小,来调整更新触发条件的数据量比例,而MySQL只能是10%,而且,因为PG还有autovacuum_analyze_threshold这个最小更新量保护机制,避免小表被频发触发统计信息收集影响性能。

在手动收集统计信息的方式上,PG和MySQL类似,都会加上读锁,MySQL加元数据读锁,不影响DML并行,PG加共享更新独占(SHARE UPDATE EXCLUSIVE),也不影响DML并行。

另外PG统计信息收集还有两个优势

统计信息的精度
MySQL统计信息的精度相对较低,尤其是在数据量较大且分布不均匀的情况下,可能无法准确地反映数据的实际情况,从而影响查询优化器的选择;而PG除了包含与 MySQL 类似的基本统计信息外,还提供了更丰富的统计内容,如多字段统计信息,可以对多个列的组合进行统计分析,为复杂的查询提供更精确的优化依据。

对性能的影响
MySQL自动收集统计信息可能会在一定程度上增加系统的负载,尤其是在数据量较大且修改频繁的情况下;而PostgreSQL的autovacuum 进程在后台自动运行,对系统性能的影响相对较小。但在进行大规模的数据操作或系统负载较高时,可能会导致一定的性能波动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值