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

news2024/10/7 4:26:04

一,

表和索引的膨胀现象

 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/

未完待续!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

强化学习原理python篇08——actor-critic

强化学习原理python篇08——actor-critic 前置知识TD ErrorREINFORCEQACAdvantage actor-critic (A2C) torch实现步骤第一步第二步第三步训练结果 Ref 本章全篇参考赵世钰老师的教材 Mathmatical-Foundation-of-Reinforcement-Learning Actor-Critic Methods 章节&#xff0c;请…

灵伴科技(Rokid)借助 Knative 实现 AI 应用云原生 Serverless 化

作者&#xff1a;朱炜栋、元毅、子白 公司介绍 Rokid 创立于 2014 年&#xff0c;是一家专注于人机交互技术的产品平台公司&#xff0c;2018 年即被评为国家高新技术企业。Rokid 作为行业的探索者、领跑者&#xff0c;目前致力于 AR 眼镜等软硬件产品的研发及以 YodaOS 操作系…

【SpringBoot3】Spring 请求处理流程,自定义返回类型处理(HttpMessageConverter)

一、Spring Boot 请求处理 1、请求处理流程 Spring Boot 的接口请求处理流程主要基于 Spring MVC 架构&#xff0c;以下是详细的请求处理流程&#xff1a; 客户端发送请求&#xff1a;客户端发送HTTP请求到Spring Boot应用的URL。 DispatcherServlet 接收请求&#xff1a;Sp…

《C程序设计》上机实验报告(五)之一维数组二维数组与字符数组

实验内容&#xff1a; 1.运行程序 #include <stdio.h> void main( ) { int i,j,iRow0,iCol0,m; int x[3][4]{{1,11,22,33},{2,28,98,38},{3,85,20,89}}; mx[0][0]; for(i0;i<3;i) for(j0;j<4;j) if (x[i][j]>m) { mx[i][j]; iRowi…

QT学习日记 | 信号与槽

目录 前言 一、初始信号与槽 1、信号与槽的本质 2、信号与槽的使用 3、内置信号、内置槽函数与自定义信号、自定义槽函数 &#xff08;1&#xff09;文档查询 &#xff08;2&#xff09;自定义信号与内置槽函数的使用 4、信号与槽函数关联关系 5、带参数的信号与槽函数…

17- OpenCV:图像矩(Image Moments)和点多边形测试

目录 一、图像矩 1、矩的概念介绍 2、相关的API 3、代码演示 二、点多边形测试 1、概念介绍-点多边形测试 2、cv::pointPolygonTest 3、代码演示 一、图像矩 引言 在数字图像处理、计算机视觉与相关领域中&#xff0c;图像矩(Image moments)是指图像的某些特定像素灰…

如何搭建良好的软件测试环境?有什么作用?

在软件开发过程中&#xff0c;测试环境是非常重要的一环。它为软件测试提供了一个模拟真实生产环境的平台&#xff0c;以确保软件的质量和稳定性。那么如何搭建良好的测试环境呢?测试环境又有什么作用呢?卓码软件测评小编将进行以下解答。 软件测试环境是指在软件测试过程中…

Windows10更新失败 错误 0x80070643、KB5034441的解决方法之二

Windows10更新失败 错误 0x80070643、KB5034441 在知乎Windows10更新失败 错误 0x80070643、KB5034441的原因分析和几个解决方法 - 知乎 参考文章进行操作&#xff0c;更详细信息自己看上面链接。 我电脑的硬盘是mbr格式&#xff0c;而且没有划分恢复分区。 Microsoft Windo…

HDFS HA 之 HA 原理

1 ZKFC解析 HA(High Availability)是HDFS支持的一个重要特性,可以有效解决Active Namenode遇到故障时,将可用的Standby节点变成新的Active状态的问题,使集群能够正常工作。目前支持冷切换和热切换两种方式。冷切换通过手动触发,缺点是不能够及时恢复集群。实际生产中以应用…

【数据结构与算法】之排序系列-20240201

【数据结构与算法】之排序系列-20240201 一、88. 合并两个有序数组二、169. 多数元素三、217. 存在重复元素四、242. 有效的字母异位词五、268. 丢失的数字六、349. 两个数组的交集七、350. 两个数组的交集 II 一、88. 合并两个有序数组 简单 给你两个按 非递减顺序 排列的整数…

Linux网络状态查看与防火墙管理

网络状态查看 netstat [选项] Netstat是一款命令行工具&#xff0c;用于显示Linux系统中网络的状态信息&#xff0c;可以显示网络连接、路由表、连接的数据统计等信息。 使用 选项 -a&#xff1a;显示所有选项&#xff0c;包括监听和未监听的端口。 -t&#xff1a;仅显示tc…

C++(17)——list的模拟实现

前面的文章中&#xff0c;介绍了&#xff0c;的模拟实现&#xff0c;本篇文章将介绍对于的模拟实现。 目录 1. list的基本结构&#xff1a; 2. list功能实现&#xff1a;尾部插入元素&#xff1a; 3. list迭代器的实现&#xff1a; 4. list功能实现&#xff1a;在任意位置前…

从零开始训练 RT-DETR模型最新版本教程说明(包含Mac、Windows、Linux端 )同之前的项目版本代码有区别

从零开始训练 RT-DETR- 最新8.1版本教程说明 本文适用Windows/Linux/Mac:从零开始使用Windows/Linux/Mac训练 RT-DETR 算法项目 《芒果 RT-DETR 目标检测算法 改进》 适用于芒果专栏改进 RT-DETR 算法 文章目录 U版 RT-DETR 算法第一步 配置环境1.1 系列配置1.2 代码执行第…

react-virtualized实现行元素不等高的虚拟列表滚动

前言&#xff1a; 当一个页面中需要接受接口返回的全部数据进行页面渲染时间&#xff0c;如果数据量比较庞大&#xff0c;前端在渲染dom的过程中需要花费时间&#xff0c;造成页面经常出现卡顿现象。 需求&#xff1a;通过虚拟加载&#xff0c;优化页面渲染速度 优点&#xff1…

探索组合模式的魅力:探索树形结构的艺术与科学

设计模式专栏&#xff1a;http://t.csdnimg.cn/nolNS 在面对层次结构和树状数据结构的软件设计任务时&#xff0c;我们如何优雅地处理单个对象与组合对象的一致性问题&#xff1f;组合模式&#xff08;Composite Pattern&#xff09;为此提供了一种简洁高效的解决方案。通过本…

网络协议 UDP协议

网络协议 UDP协议 在之前的文章中有对UDP协议套接字的使用进行讲解&#xff0c;本文主要对UDP协议进行一些理论补充。 文章目录 网络协议 UDP协议1. 概念2. UDP协议格式2.1 数据报长度2.2 校验和/检验和2.2.1 CRC校验2.2.2 MD5算法 1. 概念 UDP&#xff0c;即User Datagram P…

[office] excel2010双向条形图制作 #经验分享#微信

excel2010双向条形图制作 本教程为大家介绍一下excel2010中excel2010双向条形图制作方法。 1.选中工作区域 2.点击插入-->图表,选择条形图 3.为美观可将中间竖线可去掉 4.方法是选中竖线,右击-->删除 5.接下来将图例靠上,选中图例,右击-->设置图例格式-->图例选项…

排序算法-选择/堆排序(C语言)

1基本思想&#xff1a; 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的 数据元素排完 。 2 直接选择排序: 在元素集合 array[i]--array[n-1] 中选择关键码最大 ( 小 ) 的数据元素…

【C/C++ 07】词频统计

一、题目 读入一篇英文短文&#xff0c;去除介词、连词、冠词、副词、代词等非关键性单词后&#xff0c;统计每个单词出现的次数&#xff0c;并将单词按出现次数的降序和单词字符的升序进行显示5个单词。 二、算法 1. 通过<fstream>库创建fstream流对象&#xff0c;并从…

数学建模 - 线性规划入门:Gurobi + python

在工程管理、经济管理、科学研究、军事作战训练及日常生产生活等众多领域中&#xff0c;人们常常会遇到各种优化问题。例如&#xff0c;在生产经营中&#xff0c;我们总是希望制定最优的生产计划&#xff0c;充分利用已有的人力、物力资源&#xff0c;获得最大的经济效益&#…