postgresql|数据库|pg_repack插件的部署和使用

一,

表和索引的膨胀现象

 Postgres SQL 实现的MVCC的机制不同于 oracle , mysql innodb 的 undo tablespace 的机制。 表上所用的更新和删除等操作的行为,都不会实际的删除或修改,而是标记为死元祖 (dead rows or dead tuples),也因此,在大表进行长事务增删改的时候,表的磁盘使用空间会逐渐变大,并且,表的读写性能会随着表膨胀的程度加深而逐渐下降。

那么说人话就是,表和索引的膨胀会造成两个后果,第一是磁盘空间的占用,比如,某个几百G的大表delete 删除后,并不会释放磁盘空间,并且在删除的过程中还会引发wal日志的膨胀,而数据库服务器的磁盘空间并不是无限的,第二个就是会使得表的查询和写入性能下降,也就是查询速度降低或者插入/更新速度明显下降。

因此,我们在数据库的使用过程中,应该避免表膨胀,至少是将表膨胀控制在一个合理的,可接受的范围内,完全的避免表膨胀是确定无疑的不可能。

postgresql数据库对于表膨胀这个问题是有几种处理方式

第一,是在postgresql的主配置文件内定义autovacuum,也就是让postgresql数据库自己决定何时治理表膨胀

第二,手动vacuum 治理表膨胀

第三,CLUSTER命令治理表膨胀

第四,利用外部插件,例如pg_repack 治理表膨胀

第五,recreate table or reindex : 相当于重建表和索引。

  • 如果选择重建表的话 是类似于 create table tab_new as select * from tab_old, 然后在 创建相关索引,最后进行表名的 rename 切换。还需注意表的权限:需要重新赋权。
  • 另外这个也是需要应用系统的维护窗口时间的。
  • 如果选择重建索引的话, 类似于 reindex CONCURRENTLY index_name, 需要注意的是需要2倍的索引存储空间,进行online的索引重建。

CLUSTER背后的代码与VACUUM (FULL)相同,只是增加了一个排序。因此,CLUSTER存在和VACUUM (FULL)一样的问题:

  • CLUSTER以ACCESS EXCLUSIVE模式锁定表,锁定期间阻塞所有操作,VACUUM (FULL)也是一样的
  • 需要二倍于表的空间进行操作

对于大表来说,根据表的数据规模大小,很多时候vacuum或者CLUSTER的时候都是几个小时甚至十几个小时,而在此期间表被锁住是无法接受的,读写都有问题,锁表会造成业务的中断。

pg_repack 锁表的时间相对vacuum或者cluster来说是比较少的,大概是vacuum的锁表时间的20%,因此,pg_repack 是一个比较好的选择,但pg_repack 的使用仍然是推荐在业务低峰期使用,虽然锁表时间大幅减少。

repack 实际上是创建了一张临时表, 并在原始表上创建触发器捕获数据变化,同步到临时表中, 并在临时表中重新创建索引,最后进行临时表和原始表的切换。
工作原理和mysql 的 pt-online-schema-change 的工具是十分类似的.

下面将就pg_repack 的部署和基本使用做一个介绍

二,

表膨胀治理的时机

在表膨胀治理之前,我们需要了解哪些表需要治理,在表膨胀治理之后,我们需要清楚的知道,具体治理了多少表膨胀

监控数据库级别的膨胀:Show database bloat - PostgreSQL wiki

SQL语句如下:

这个SQL语句比较简略,主要关注上图标识的这两行,wastedbytes的值越大,表明表膨胀越严重

SELECT
  current_database(), schemaname, tablename, /*reltuples::bigint, relpages::bigint, otta,*/
  ROUND((CASE WHEN otta=0 THEN 0.0 ELSE sml.relpages::float/otta END)::numeric,1) AS tbloat,
  CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::BIGINT END AS wastedbytes,
  iname, /*ituples::bigint, ipages::bigint, iotta,*/
  ROUND((CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages::float/iotta END)::numeric,1) AS ibloat,
  CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes
FROM (
  SELECT
    schemaname, tablename, cc.reltuples, cc.relpages, bs,
    CEIL((cc.reltuples*((datahdr+ma-
      (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)) AS otta,
    COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
    COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
  FROM (
    SELECT
      ma,bs,schemaname,tablename,
      (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
      (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
    FROM (
      SELECT
        schemaname, tablename, hdr, ma, bs,
        SUM((1-null_frac)*avg_width) AS datawidth,
        MAX(null_frac) AS maxfracsum,
        hdr+(
          SELECT 1+count(*)/8
          FROM pg_stats s2
          WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename
        ) AS nullhdr
      FROM pg_stats s, (
        SELECT
          (SELECT current_setting('block_size')::numeric) AS bs,
          CASE WHEN substring(v,12,3) IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr,
          CASE WHEN v ~ 'mingw32' THEN 8 ELSE 4 END AS ma
        FROM (SELECT version() AS v) AS foo
      ) AS constants
      GROUP BY 1,2,3,4,5
    ) AS foo
  ) AS rs
  JOIN pg_class cc ON cc.relname = rs.tablename
  JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = rs.schemaname AND nn.nspname <> 'information_schema'
  LEFT JOIN pg_index i ON indrelid = cc.oid
  LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
) AS sml
ORDER BY wastedbytes DESC

监控表级别的膨胀:

https://github.com/ioguix/pgsql-bloat-estimation/blob/master/table/table_bloat.sql

注:稍作修改,屏蔽了系统库

该SQL语句执行完后,重点关注上图标识的地方就行了,blooat_pct 越大,表明表膨胀越严重

/* WARNING: executed with a non-superuser role, the query inspect only tables and materialized view (9.3+) you are granted to read.
* This query is compatible with PostgreSQL 9.0 and more
*/
SELECT current_database(), schemaname, tblname, bs*tblpages AS real_size,
  (tblpages-est_tblpages)*bs AS extra_size,
  CASE WHEN tblpages > 0 AND tblpages - est_tblpages > 0
    THEN 100 * (tblpages - est_tblpages)/tblpages::float
    ELSE 0
  END AS extra_pct, fillfactor,
  CASE WHEN tblpages - est_tblpages_ff > 0
    THEN (tblpages-est_tblpages_ff)*bs
    ELSE 0
  END AS bloat_size,
  CASE WHEN tblpages > 0 AND tblpages - est_tblpages_ff > 0
    THEN 100 * (tblpages - est_tblpages_ff)/tblpages::float
    ELSE 0
  END AS bloat_pct, is_na
  -- , tpl_hdr_size, tpl_data_size, (pst).free_percent + (pst).dead_tuple_percent AS real_frag -- (DEBUG INFO)
FROM (
  SELECT ceil( reltuples / ( (bs-page_hdr)/tpl_size ) ) + ceil( toasttuples / 4 ) AS est_tblpages,
    ceil( reltuples / ( (bs-page_hdr)*fillfactor/(tpl_size*100) ) ) + ceil( toasttuples / 4 ) AS est_tblpages_ff,
    tblpages, fillfactor, bs, tblid, schemaname, tblname, heappages, toastpages, is_na
    -- , tpl_hdr_size, tpl_data_size, pgstattuple(tblid) AS pst -- (DEBUG INFO)
  FROM (
    SELECT
      ( 4 + tpl_hdr_size + tpl_data_size + (2*ma)
        - CASE WHEN tpl_hdr_size%ma = 0 THEN ma ELSE tpl_hdr_size%ma END
        - CASE WHEN ceil(tpl_data_size)::int%ma = 0 THEN ma ELSE ceil(tpl_data_size)::int%ma END
      ) AS tpl_size, bs - page_hdr AS size_per_block, (heappages + toastpages) AS tblpages, heappages,
      toastpages, reltuples, toasttuples, bs, page_hdr, tblid, schemaname, tblname, fillfactor, is_na
      -- , tpl_hdr_size, tpl_data_size
    FROM (
      SELECT
        tbl.oid AS tblid, ns.nspname AS schemaname, tbl.relname AS tblname, tbl.reltuples,
        tbl.relpages AS heappages, coalesce(toast.relpages, 0) AS toastpages,
        coalesce(toast.reltuples, 0) AS toasttuples,
        coalesce(substring(
          array_to_string(tbl.reloptions, ' ')
          FROM 'fillfactor=([0-9]+)')::smallint, 100) AS fillfactor,
        current_setting('block_size')::numeric AS bs,
        CASE WHEN version()~'mingw32' OR version()~'64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS ma,
        24 AS page_hdr,
        23 + CASE WHEN MAX(coalesce(s.null_frac,0)) > 0 THEN ( 7 + count(s.attname) ) / 8 ELSE 0::int END
           + CASE WHEN bool_or(att.attname = 'oid' and att.attnum < 0) THEN 4 ELSE 0 END AS tpl_hdr_size,
        sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 0) ) AS tpl_data_size,
        bool_or(att.atttypid = 'pg_catalog.name'::regtype)
          OR sum(CASE WHEN att.attnum > 0 THEN 1 ELSE 0 END) <> count(s.attname) AS is_na
      FROM pg_attribute AS att
        JOIN pg_class AS tbl ON att.attrelid = tbl.oid
        JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace
        LEFT JOIN pg_stats AS s ON s.schemaname=ns.nspname
          AND s.tablename = tbl.relname AND s.inherited=false AND s.attname=att.attname
        LEFT JOIN pg_class AS toast ON tbl.reltoastrelid = toast.oid
      WHERE NOT att.attisdropped
        AND tbl.relkind in ('r','m')
				AND schemaname not IN('pg_catalog','information_schema','repack')
      GROUP BY 1,2,3,4,5,6,7,8,9,10
      ORDER BY 2,3
    ) AS s
  ) AS s2
) AS s3
-- WHERE NOT is_na
--   AND tblpages*((pst).free_percent + (pst).dead_tuple_percent)::float4/100 >= 1
ORDER BY schemaname, tblname;

 监控索引级别的膨胀:

https://github.com/ioguix/pgsql-bloat-estimation/blob/master/btree/btree_bloat.sql

注:稍作修改,屏蔽了系统库

-- WARNING: executed with a non-superuser role, the query inspect only index on tables you are granted to read.
-- WARNING: rows with is_na = 't' are known to have bad statistics ("name" type is not supported).
-- This query is compatible with PostgreSQL 8.2 and after
SELECT current_database(), nspname AS schemaname, tblname, idxname, bs*(relpages)::bigint AS real_size,
  bs*(relpages-est_pages)::bigint AS extra_size,
  100 * (relpages-est_pages)::float / relpages AS extra_pct,
  fillfactor,
  CASE WHEN relpages > est_pages_ff
    THEN bs*(relpages-est_pages_ff)
    ELSE 0
  END AS bloat_size,
  100 * (relpages-est_pages_ff)::float / relpages AS bloat_pct,
  is_na
  -- , 100-(pst).avg_leaf_density AS pst_avg_bloat, est_pages, index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples, relpages -- (DEBUG INFO)
FROM (
  SELECT coalesce(1 +
         ceil(reltuples/floor((bs-pageopqdata-pagehdr)/(4+nulldatahdrwidth)::float)), 0 -- ItemIdData size + computed avg size of a tuple (nulldatahdrwidth)
      ) AS est_pages,
      coalesce(1 +
         ceil(reltuples/floor((bs-pageopqdata-pagehdr)*fillfactor/(100*(4+nulldatahdrwidth)::float))), 0
      ) AS est_pages_ff,
      bs, nspname, tblname, idxname, relpages, fillfactor, is_na
      -- , pgstatindex(idxoid) AS pst, index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples -- (DEBUG INFO)
  FROM (
      SELECT maxalign, bs, nspname, tblname, idxname, reltuples, relpages, idxoid, fillfactor,
            ( index_tuple_hdr_bm +
                maxalign - CASE -- Add padding to the index tuple header to align on MAXALIGN
                  WHEN index_tuple_hdr_bm%maxalign = 0 THEN maxalign
                  ELSE index_tuple_hdr_bm%maxalign
                END
              + nulldatawidth + maxalign - CASE -- Add padding to the data to align on MAXALIGN
                  WHEN nulldatawidth = 0 THEN 0
                  WHEN nulldatawidth::integer%maxalign = 0 THEN maxalign
                  ELSE nulldatawidth::integer%maxalign
                END
            )::numeric AS nulldatahdrwidth, pagehdr, pageopqdata, is_na
            -- , index_tuple_hdr_bm, nulldatawidth -- (DEBUG INFO)
      FROM (
          SELECT n.nspname, i.tblname, i.idxname, i.reltuples, i.relpages,
              i.idxoid, i.fillfactor, current_setting('block_size')::numeric AS bs,
              CASE -- MAXALIGN: 4 on 32bits, 8 on 64bits (and mingw32 ?)
                WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8
                ELSE 4
              END AS maxalign,
              /* per page header, fixed size: 20 for 7.X, 24 for others */
              24 AS pagehdr,
              /* per page btree opaque data */
              16 AS pageopqdata,
              /* per tuple header: add IndexAttributeBitMapData if some cols are null-able */
              CASE WHEN max(coalesce(s.null_frac,0)) = 0
                  THEN 8 -- IndexTupleData size
                  ELSE 8 + (( 32 + 8 - 1 ) / 8) -- IndexTupleData size + IndexAttributeBitMapData size ( max num filed per index + 8 - 1 /8)
              END AS index_tuple_hdr_bm,
              /* data len: we remove null values save space using it fractionnal part from stats */
              sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024)) AS nulldatawidth,
              max( CASE WHEN i.atttypid = 'pg_catalog.name'::regtype THEN 1 ELSE 0 END ) > 0 AS is_na
          FROM (
              SELECT ct.relname AS tblname, ct.relnamespace, ic.idxname, ic.attpos, ic.indkey, ic.indkey[ic.attpos], ic.reltuples, ic.relpages, ic.tbloid, ic.idxoid, ic.fillfactor,
                  coalesce(a1.attnum, a2.attnum) AS attnum, coalesce(a1.attname, a2.attname) AS attname, coalesce(a1.atttypid, a2.atttypid) AS atttypid,
                  CASE WHEN a1.attnum IS NULL
                  THEN ic.idxname
                  ELSE ct.relname
                  END AS attrelname
              FROM (
                  SELECT idxname, reltuples, relpages, tbloid, idxoid, fillfactor, indkey,
                      pg_catalog.generate_series(1,indnatts) AS attpos
                  FROM (
                      SELECT ci.relname AS idxname, ci.reltuples, ci.relpages, i.indrelid AS tbloid,
                          i.indexrelid AS idxoid,
                          coalesce(substring(
                              array_to_string(ci.reloptions, ' ')
                              from 'fillfactor=([0-9]+)')::smallint, 90) AS fillfactor,
                          i.indnatts,
                          pg_catalog.string_to_array(pg_catalog.textin(
                              pg_catalog.int2vectorout(i.indkey)),' ')::int[] AS indkey
                      FROM pg_catalog.pg_index i
                      JOIN pg_catalog.pg_class ci ON ci.oid = i.indexrelid
                      WHERE ci.relam=(SELECT oid FROM pg_am WHERE amname = 'btree')
                      AND ci.relpages > 0
                  ) AS idx_data
              ) AS ic
              JOIN pg_catalog.pg_class ct ON ct.oid = ic.tbloid
              LEFT JOIN pg_catalog.pg_attribute a1 ON
                  ic.indkey[ic.attpos] <> 0
                  AND a1.attrelid = ic.tbloid
                  AND a1.attnum = ic.indkey[ic.attpos]
              LEFT JOIN pg_catalog.pg_attribute a2 ON
                  ic.indkey[ic.attpos] = 0
                  AND a2.attrelid = ic.idxoid
                  AND a2.attnum = ic.attpos
            ) i
            JOIN pg_catalog.pg_namespace n ON n.oid = i.relnamespace
            JOIN pg_catalog.pg_stats s ON s.schemaname = n.nspname
                                      AND s.tablename = i.attrelname
                                      AND s.attname = i.attname
																			AND schemaname not IN('pg_catalog','information_schema','repack')
            GROUP BY 1,2,3,4,5,6,7,8,9,10,11
      ) AS rows_data_stats
  ) AS rows_hdr_pdg_stats
) AS relation_stats
ORDER BY nspname, tblname, idxname;

三,

pg_repack的部署

pg_repack现在支持到postgresql-16版本,下载地址:https://github.com/reorg/pg_repack/releases/tag/ver_1.5.0

下载下来的压缩包上传到服务器后,进入解压目录

先安装编译依赖:

yum install openssl openssl-devel readline readline-devel -y

然后编译三连就好了:

make && make install

编译日志如下:

[root@centos10 pg_repack-ver_1.5.0]# make
make[1]: Entering directory `/root/pg_repack-ver_1.5.0/bin'
gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 pg_repack.o pgut/pgut.o pgut/pgut-fe.o  -L/data/pgsql/lib   -Wl,--as-needed -Wl,-rpath,'/data/pgsql/lib',--enable-new-dtags  -L/data/pgsql/lib -lpq -L/data/pgsql/lib -lpgcommon -lpgport -lpthread -lz -lreadline -lrt -lcrypt -ldl -lm -o pg_repack
make[1]: Leaving directory `/root/pg_repack-ver_1.5.0/bin'
make[1]: Entering directory `/root/pg_repack-ver_1.5.0/lib'
gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -fPIC -DREPACK_VERSION=1.5.0 -I. -I./ -I/data/pgsql/include/server -I/data/pgsql/include/internal  -D_GNU_SOURCE   -c -o repack.o repack.c
gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -fPIC -DREPACK_VERSION=1.5.0 -I. -I./ -I/data/pgsql/include/server -I/data/pgsql/include/internal  -D_GNU_SOURCE   -c -o pgut/pgut-spi.o pgut/pgut-spi.c
( echo '{ global:'; gawk '/^[^#]/ {printf "%s;\n",$1}' exports.txt; echo ' local: *; };' ) >exports.list
gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -fPIC -shared -Wl,--version-script=exports.list -o pg_repack.so repack.o pgut/pgut-spi.o -L/data/pgsql/lib    -Wl,--as-needed -Wl,-rpath,'/data/pgsql/lib',--enable-new-dtags  
sed 's,REPACK_VERSION,1.5.0,g' pg_repack.sql.in \
| sed 's,relhasoids,false,g'> pg_repack--1.5.0.sql;
sed 's,REPACK_VERSION,1.5.0,g' pg_repack.control.in > pg_repack.control
make[1]: Leaving directory `/root/pg_repack-ver_1.5.0/lib'
make[1]: Entering directory `/root/pg_repack-ver_1.5.0/regress'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/root/pg_repack-ver_1.5.0/regress'
[root@centos10 pg_repack-ver_1.5.0]# echo $?
0
[root@centos10 pg_repack-ver_1.5.0]# make install
make[1]: Entering directory `/root/pg_repack-ver_1.5.0/bin'
/usr/bin/mkdir -p '/data/pgsql/bin'
/usr/bin/install -c  pg_repack '/data/pgsql/bin'
make[1]: Leaving directory `/root/pg_repack-ver_1.5.0/bin'
make[1]: Entering directory `/root/pg_repack-ver_1.5.0/lib'
/usr/bin/mkdir -p '/data/pgsql/lib'
/usr/bin/mkdir -p '/data/pgsql/share/extension'
/usr/bin/mkdir -p '/data/pgsql/share/extension'
/usr/bin/install -c -m 755  pg_repack.so '/data/pgsql/lib/pg_repack.so'
/usr/bin/install -c -m 644 .//pg_repack.control '/data/pgsql/share/extension/'
/usr/bin/install -c -m 644  pg_repack--1.5.0.sql pg_repack.control '/data/pgsql/share/extension/'
make[1]: Leaving directory `/root/pg_repack-ver_1.5.0/lib'
make[1]: Entering directory `/root/pg_repack-ver_1.5.0/regress'
make[1]: Nothing to be done for `install'.
make[1]: Leaving directory `/root/pg_repack-ver_1.5.0/regress'
[root@centos10 pg_repack-ver_1.5.0]# 
[root@centos10 pg_repack-ver_1.5.0]# cd
[root@centos10 ~]# whereis pg_repack
pg_repack: /data/pgsql/bin/pg_repack

登录postgresql的命令行,激活插件,这里是哪个数据库需要此插件就切换到哪个数据库内:

比如,我需要在名为test的数据库内使用此插件:

\c test
create extension pg_repack;

此插件激活后,将会看到一个名为repack的scheme和一系列相关函数和两个视图:

四,

 pg_repack的表膨胀治理能力测试

1,

创建新库和大表

新库名称为test,大表的创建语句如下:

大表名称为testpg,数据量级为2000w,只有两列数据

create or replace function gen_id(  
 a date,  
 b date  
)   
returns text as $$  
select lpad((random()*99)::int::text, 3, '0') ||   
    lpad((random()*99)::int::text, 3, '0') ||   
    lpad((random()*99)::int::text, 3, '0') ||   
    to_char(a + (random()*(b-a))::int, 'yyyymmdd') ||   
    lpad((random()*99)::int::text, 3, '0') ||   
    random()::int ||   
    (case when random()*10 >9 then 'xy' else (random()*9)::int::text end ) ;  
$$ language sql strict;



CREATE SEQUENCE test START 1;
create table if not exists testpg (
	"id" int8 not null DEFAULT nextval('test'::regclass),
	CONSTRAINT "user_vendorcode_pkey" PRIMARY KEY ("id"),
	"suijishuzi" VARCHAR ( 255 ) COLLATE "pg_catalog"."default"
);


insert into testpg SELECT generate_series(1,20000000) as xm, gen_id('1949-01-01', '2023-10-16') as num;

2,

查看大表大小和该表的膨胀情况,SQL语句如下:

SELECT
table_schema,
table_name,
pg_size_pretty(table_size) AS table_size,
pg_size_pretty(indexes_size) AS indexes_size,
pg_size_pretty(total_size) AS total_size
FROM (
SELECT
table_schema,
table_name,
pg_table_size(table_name) AS table_size,
pg_indexes_size(table_name) AS indexes_size,
pg_total_relation_size(table_name) AS total_size
FROM (
SELECT table_schema,('"' || table_schema || '"."' || table_name || '"') AS table_name
FROM information_schema.tables
) AS all_tables
ORDER BY total_size DESC
) AS pretty_sizes where table_schema not in ('pg_catalog','information_schema','repack');

输出如下:

使用上面的第二个查询表膨胀的语句,结果如下:

3,

大量更新testpg这个表,人为制造表膨胀:

UPDATE testpg set suijishuzi='123456789' WHERE suijishuzi like'%1%'

查看表大小和膨胀率:

可以看到,膨胀率达到了45%

4,

pg_repack表膨胀治理:

[root@centos10 ~]# su - postgres -c "/data/pgsql/bin/pg_repack -d test  -t public.testpg"
INFO: repacking table "public.testpg"

在膨胀治理期间,可以正常的对该表读写,治理完毕后,查看表大小和表膨胀率:

可以看到,膨胀治理完全成功,

观察磁盘使用,可以看到,符合本次膨胀治理的结果:

[root@centos10 ~]# du -sh /data/pgsql/data/
4.0G	/data/pgsql/data/
[root@centos10 ~]# du -sh /data/pgsql/data/
2.7G	/data/pgsql/data/

未完待续!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/363633.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

非鸿蒙官方低代码源码生成器

介绍 鸿蒙低代码可视化开发神器快速对鸿蒙ArkUI生成源码&#xff0c;结合类似小程序类似设计&#xff0c;页面设计底部菜单&#xff0c;支持宫格组件、轮播图、图文列表、图片组件、文本内容组件&#xff0c;快速对接第三方HttpApi。通过鸿蒙扩展axios扩展库加载数据源&#x…

jmeter+nmon+crontab简单的执行接口定时压测

一、概述 临时接到任务要对系统的接口进行压测&#xff0c;上面的要求就是&#xff1a;压测&#xff0c;并发2000 在不熟悉系统的情况下&#xff0c;按目前的需求&#xff0c;需要做的步骤&#xff1a; 需要有接口脚本需要能监控系统性能需要能定时执行脚本 二、观察 >…

Spring的事件监听机制

这里写自定义目录标题 1. 概述&#xff08;重点&#xff09;2. ApplicationEventMulticaster2.1 SimpleApplicationEventMulticaster2.2 AbstractApplicationEventMulticaster 3. ApplicationListener3.1 注册监听器3.2 自定义 4. SpringApplicationRunListeners 1. 概述&#…

协会认证!百望云荣获信创工委会年度“卓越贡献成员单位”称号

当前&#xff0c;新一轮科技革命和产业变革正加速重塑全球经济结构&#xff0c;强化企业科技创新的主体地位&#xff0c;推动创新链、产业链、人才链深度融合&#xff0c;加快科技成果产业化进程至关重要。 近日&#xff0c;中国电子工业标准化技术协会信息技术应用创新工作委员…

对付勒索病毒,复杂的往往无法落地

一道道复杂门墙防护安全&#xff0c; 还是一个精密的锁更安全&#xff1f; &#x1f447;&#x1f447;&#x1f447; 在网络数据安全问题频发的当下&#xff0c;除了常规的备份、灾备措施以外&#xff0c;企业是否有做好应对最坏情况的准备&#xff1f;一旦病毒绕过了一道道…

shell - 免交互

一.Here Document 免交互 1. 交互的概念 交互&#xff1a;当计算机播放某多媒体程序的时候&#xff0c;编程人员可以发出指令控制该程序的运行&#xff0c;而不是程序单方面执行下去&#xff0c;程序在接受到编程人员相应的指令后而相应地做出反应。 对于Linux操作系统中&…

ztest中ddof起什么作用

⭐️ statsmodels 中 ztest 基本使用 statsmodels 也是一个强大的统计分析库&#xff0c;提供了丰富的统计模型和检验功能。对于 Z 检验&#xff0c;statsmodels 提供了 ztest 函数。 以下是使用 statsmodels 进行 Z 检验的示例&#xff1a; from statsmodels.stats.weights…

ElementUI 组件:Container 布局容器

ElementUI安装与使用指南 Container 布局容器 点击下载learnelementuispringboot项目源码 效果图 el-container.vue&#xff08;Container 布局容器&#xff09;页面效果图 项目里el-container.vue代码 <script> import PagePath from "/components/PagePat…

[NOIP2011 提高组] 聪明的质监员

[NOIP2011 提高组] 聪明的质监员 题目描述 小T 是一名质量监督员&#xff0c;最近负责检验一批矿产的质量。这批矿产共有 n n n 个矿石&#xff0c;从 1 1 1 到 n n n 逐一编号&#xff0c;每个矿石都有自己的重量 w i w_i wi​ 以及价值 v i v_i vi​ 。检验矿产的流程…

Python代码覆盖率工具

Coverage.py是一个用于测量Python程序代码覆盖率的工具。它监视您的程序&#xff0c;注意代码的哪些部分已经执行&#xff0c;然后分析源代码&#xff0c;以确定哪些代码本可以执行&#xff0c;但没有执行。 覆盖率测量通常用于衡量测试的有效性。它可以显示代码的哪些部分正在…

S275 4G网络IO模块:智能酒店的理想选择

行业背景 随着物联网技术的发展&#xff0c;酒店服务也变得更加“智能”——自动灯光效果、室内温湿度控制、各种人性化操作等贴心服务&#xff0c;带给顾客真正的宾至如归之感。 同时&#xff0c;智慧酒店更为管理者提供了高效的管理手段&#xff0c;将酒店物耗、能耗、人员…

全网最简单的幻兽帕鲁服务器搭建教程

幻兽帕鲁是一款备受欢迎的多人在线游戏&#xff0c;为了提供更好的游戏体验&#xff0c;许多玩家选择自行搭建服务器。本文将指导大家如何简单快速地搭建幻兽帕鲁服务器&#xff0c;轻松享受游戏的乐趣。 第一步&#xff1a;购买游戏联机服务器 购买入口&#xff1a;https://tx…

【八大排序】直接插入排序 | 希尔排序 + 图文详解!!

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C语言进阶之路 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 一、排序的概念二、直接插入排序2.1 基本思想2.2 适用说明2.3 过程图示2.4 代码实现2.…

排序之计数排序

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

vue+element 换肤功能

1.首先建深色和浅色两个主题样式变量样式表&#xff0c;样式表名和按钮中传入的值一样&#xff0c;本例中起名为default.scss和dark.scss 2.在data中定义主题变量名 zTheme:‘defalut’&#xff0c;默认引用defalut.scss, 在点击按钮时切换引用的样式表&#xff0c;达到换肤效果…

Codeforces Round 884 E. Great Grids

E. Great Grids 题意 一个 n m n \times m nm 的网格图是 g o o d good good 的当且仅当&#xff1a; 每个网格的字符是 A 、 B 、 C A、B、C A、B、C 中的一种每一个 2 2 2 \times 2 22 的子格都包含三种不同的字符相邻的格子字符不一样 现在给定 k k k 个限制条件&…

【Redis】实现缓存及相关问题

Redis实现缓存及相关问题 认识缓存 缓存就是数据交换的缓冲区&#xff0c;是存贮数据的临时地方&#xff0c;一般读写性能较高。 缓存的作用&#xff1a; 降低后端负载提高读写效率&#xff0c;降低响应时间 缓存的成本&#xff1a; 数据一致性成本代码维护成本运维成本 …

PXE高效批量装机

一、系统安装 1. 系统装机的三种引导方式 1. 硬盘安装 2. 光驱&#xff08;u盘&#xff09;安装 3. 网络启动 pxe 2.系统安装过程 加载boot loader Boot Loader 是在操作系统内核运行之前运行的一段小程序。通过这段小程序&#xff0c;我们可以初始化硬件设备、建立内…

C#使用OpenCvSharp4库中5个基础函数-灰度化、高斯模糊、Canny边缘检测、膨胀、腐蚀

C#使用OpenCvSharp4库中5个基础函数-灰度化、高斯模糊、Canny边缘检测、膨胀、腐蚀 使用OpenCV可以对彩色原始图像进行基本的处理&#xff0c;涉及到5个常用的处理&#xff1a; 灰度化 模糊处理 Canny边缘检测 膨胀 腐蚀 1、测试图像lena.jpg 本例中我们采用数字图像处…

day39_mysql

今日内容 0 复习昨日 1 DML 2 约束 3 DQL 0 复习昨日 1 什么是数据库(Database)? 用来组织,存储,管理数据的仓库 2 什么是数据库管理系统(Database Management System-DBMS)? 用来管理数据库的一个软件 3 数据库分类 关系型数据库,Oracle,Mysql,SqlServer,DB2非关系数据库,Re…