概述
pg_repack
是一个 PostgreSQL 扩展,它允许您从表和索引中删除膨胀,并可选择恢复聚集索引的物理顺序。与CLUSTER
和VACUUM FULL
不同,它在线工作,在处理过程中不会对已处理的表持有独占锁。pg_repack
启动效率高,性能与直接使用 CLUSTER
相当。
它会为待重建的表创建一份副本。首先取一份全量快照,将所有活元组写入新表,并通过触发器将所有针对原表的变更同步至新表,最后通过重命名,使用新的紧实副本替换老表。而对于索引,则是通过PostgreSQL的CREATE (DROP) INDEX CONCURRENTLY
完成的。
pg_repack
是pg_reorg
项目的一个分支。
您可以选择以下方法之一进行重组:
- 在线
CLUSTER
(按簇索引排序) - 按指定列排序
- 在线
VACUUM FULL
(仅包装行) - 仅重建或重定位表的索引
注意:
- 只有超级用户才能使用该实用程序。
- 目标表必须有一个
PRIMARY KEY
,或者至少有一个NOT NULL
列上的UNIQUE
索引。 - 重整开始之前,最好取消掉所有正在进行的Vacuum任务。
- 对索引做重整之前,最好能手动清理掉可能正在使用该索引的查询。
- 如果出现异常的情况(警如中途强制退出),有可能会留下未清理的垃圾,需要手工清理。
- 当完成重整,进行重命名替换时,会产生巨量的WAL,有可能会导致复制延迟,而且无法取消。
- 重整特别大的表时,需要预留至少与该表及其索引相同大小的磁盘空间,需要特别小心,手动检查。
- 如果遇到写入速度非常快的,最后阶段replylog的时候,只能等。
要求
- PostgreSQL 版本
PostgreSQL 9.4、9.5、9.6、10、11、12、13、14、15
- 磁盘
执行全表重新打包需要大约两倍于目标表及其索引的可用磁盘空间。例如,如果要重组的表和索引的总大小为 1GB,则需要额外的 2GB 磁盘空间。
下载
墨天轮地址:https://www.modb.pro/doc/96162
github地址:https://github.com/reorg/pg_repack
[root@lyp ~]# ll pg_repack-1.4.8.zip
-rw-r--r--. 1 root root 126919 Jan 3 15:57 pg_repack-1.4.8.zip
[root@lyp ~]#
安装
pg_repack
可以在 UNIX 或 Linux 上使用make构建。
自动使用 PGXS 构建框架。在构建之前,您可能需要安装 PostgreSQL 开发包(postgresql-devel
等)并将包含pg_config
的目录添加到您的$PATH
中。然后你可以运行:
$ cd pg_repack
$ make
$ sudo make install
[root@lyp ~]# export PGHOME=/opt/pgsql13.2
[root@lyp ~]# export PATH=$HOME/bin:$PGHOME/bin:$PATH
[root@lyp ~]#
[root@lyp ~]# cd pg_repack-1.4.8/
[root@lyp pg_repack-1.4.8]# ll
total 16
drwxr-xr-x. 3 root root 107 Jan 4 00:22 bin
-rw-r--r--. 1 root root 1662 Oct 3 19:24 COPYRIGHT
drwxr-xr-x. 2 root root 121 Oct 3 19:24 doc
drwxr-xr-x. 3 root root 248 Jan 4 00:22 lib
-rw-r--r--. 1 root root 1616 Oct 3 19:24 Makefile
-rw-r--r--. 1 root root 1286 Oct 3 19:24 META.json
drwxr-xr-x. 2 root root 219 Oct 3 19:24 msvc
-rw-r--r--. 1 root root 2133 Oct 3 19:24 README.rst
drwxr-xr-x. 4 root root 96 Oct 3 19:24 regress
drwxr-xr-x. 2 root root 54 Oct 3 19:24 SPECS
[root@lyp pg_repack-1.4.8]#
[root@lyp pg_repack-1.4.8]#
[root@lyp pg_repack-1.4.8]# make
make[1]: Entering directory `/root/pg_repack-1.4.8/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 -I/opt/pgsql13.2/include -DREPACK_VERSION=1.4.8 -I. -I./ -I/opt/pgsql13.2/include/server -I/opt/pgsql13.2/include/internal -D_GNU_SOURCE -c -o pg_repack.o pg_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 -I/opt/pgsql13.2/include -DREPACK_VERSION=1.4.8 -I. -I./ -I/opt/pgsql13.2/include/server -I/opt/pgsql13.2/include/internal -D_GNU_SOURCE -c -o pgut/pgut.o pgut/pgut.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 -I/opt/pgsql13.2/include -DREPACK_VERSION=1.4.8 -I. -I./ -I/opt/pgsql13.2/include/server -I/opt/pgsql13.2/include/internal -D_GNU_SOURCE -c -o pgut/pgut-fe.o pgut/pgut-fe.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 pg_repack.o pgut/pgut.o pgut/pgut-fe.o -L/opt/pgsql13.2/lib -Wl,--as-needed -Wl,-rpath,'/opt/pgsql13.2/lib',--enable-new-dtags -L/opt/pgsql13.2/lib -lpq -L/opt/pgsql13.2/lib -lpgcommon -lpgport -lpthread -lz -lreadline -lrt -ldl -lm -o pg_repack
make[1]: Leaving directory `/root/pg_repack-1.4.8/bin'
make[1]: Entering directory `/root/pg_repack-1.4.8/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.4.8 -I. -I./ -I/opt/pgsql13.2/include/server -I/opt/pgsql13.2/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.4.8 -I. -I./ -I/opt/pgsql13.2/include/server -I/opt/pgsql13.2/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/opt/pgsql13.2/lib -Wl,--as-needed -Wl,-rpath,'/opt/pgsql13.2/lib',--enable-new-dtags
sed 's,REPACK_VERSION,1.4.8,g' pg_repack.sql.in \
| sed 's,relhasoids,false,g'> pg_repack--1.4.8.sql;
sed 's,REPACK_VERSION,1.4.8,g' pg_repack.control.in > pg_repack.control
make[1]: Leaving directory `/root/pg_repack-1.4.8/lib'
make[1]: Entering directory `/root/pg_repack-1.4.8/regress'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/root/pg_repack-1.4.8/regress'
[root@lyp pg_repack-1.4.8]#
[root@lyp pg_repack-1.4.8]#
[root@lyp pg_repack-1.4.8]#
[root@lyp pg_repack-1.4.8]# make install
make[1]: Entering directory `/root/pg_repack-1.4.8/bin'
/usr/bin/mkdir -p '/opt/pgsql13.2/bin'
/usr/bin/install -c pg_repack '/opt/pgsql13.2/bin'
make[1]: Leaving directory `/root/pg_repack-1.4.8/bin'
make[1]: Entering directory `/root/pg_repack-1.4.8/lib'
/usr/bin/mkdir -p '/opt/pgsql13.2/lib'
/usr/bin/mkdir -p '/opt/pgsql13.2/share/extension'
/usr/bin/mkdir -p '/opt/pgsql13.2/share/extension'
/usr/bin/install -c -m 755 pg_repack.so '/opt/pgsql13.2/lib/pg_repack.so'
/usr/bin/install -c -m 644 .//pg_repack.control '/opt/pgsql13.2/share/extension/'
/usr/bin/install -c -m 644 pg_repack--1.4.8.sql pg_repack.control '/opt/pgsql13.2/share/extension/'
make[1]: Leaving directory `/root/pg_repack-1.4.8/lib'
make[1]: Entering directory `/root/pg_repack-1.4.8/regress'
make[1]: Nothing to be done for `install'.
make[1]: Leaving directory `/root/pg_repack-1.4.8/regress'
[root@lyp pg_repack-1.4.8]#
安装后,在你要处理的数据库中加载pg_repack
扩展。pg_repack
被打包为一个扩展,所以你可以执行:
$ psql -c "CREATE EXTENSION pg_repack" -d test
[postgres@lyp ~]$ psql -c "CREATE EXTENSION pg_repack" -d test
CREATE EXTENSION
[postgres@lyp ~]$ psql -d test
psql (13.2)
Type "help" for help.
test=# \dx pg_repack
List of installed extensions
Name | Version | Schema | Description
-----------+---------+--------+--------------------------------------------------------------
pg_repack | 1.4.8 | public | Reorganize tables in PostgreSQL databases with minimal locks
(1 row)
test=#
您可以使用DROP EXTENSION pg_repack
删除 pg_repack
或仅删除repack
模式。
如果你是从以前版本的 pg_repack
或 pg_reorg
升级,只需如上所述从数据库中删除旧版本并安装新版本。
用法
pg_repack [选项] ... [数据库名称]
可以在OPTIONS
中指定以下选项。
- 选项:
-a, --all 重新打包所有数据库
-t, --table=TABLE 仅重新打包特定表
-I, --parent-table=TABLE 重新打包特定的父表及其继承者
-c, --schema=SCHEMA 仅在特定模式中重新打包表
-s, --tablespace=TBLSPC 将重新打包的表移动到新的表空间
-S, --moveidx 将重新打包的索引也移动到TBLSPC
-o, --order-by=COLUMNS 按列而不是簇键排序
-n, --no-order 做 vacuum full 而不是 cluster
-N, --dry-run 打印将被重新包装的内容并退出
-j, --jobs=NUM 为每个表使用这么多并行作业
-i, --index=INDEX 只移动指定的索引
-x, --only-indexes 只移动指定表的索引
-T, --wait-timeout=SECS 超时以取消冲突的其他后端
-D, --no-kill-backend 超时时不要杀死其他后端
-Z, --no-analyze 最后不分析
-k, --no-superuser-check 跳过客户端中的超级用户检查
-C, --exclude-extension 不要重新打包属于特定扩展名的表 - 连接选项:
-d, --dbname=DBNAME 要连接的数据库
-h, --host=HOSTNAME 数据库服务器主机或套接字目录
-p, --port=PORT 数据库服务器端口
-U, --username=USERNAME 连接的用户名
-w, --no-password 从不提示输入密码
-W, --password 强制密码提示 - 通用选项:
-e, --echo 回显查询
-E, --elevel=LEVEL 设置输出消息级别
–help 显示此帮助,然后退出
–version 输出版本信息,然后退出
重组选项
- -a , --all尝试重新打包集群的所有数据库。将跳过未安装pg_repack扩展的数据库 。
- -t TABLE, --table=TABLE仅重组指定的表。可以通过编写多个-t开关来重组多个表。默认情况下,重组目标数据库中所有符合条件的表。
- -I TABLE , --parent-table=TABLE重组指定的表及其继承者。可以通过编写多个-I开关来重组多个表层次结构。
- -c , –schema仅重新打包指定模式中的表。可以通过编写多个-c开关来重新打包多个模式。可以与--tablespace结合使用以将表移动到不同的表空间。
- -o COLUMNS [,...] , --order-by=COLUMNS [,...]执行按指定列排序的在线 CLUSTER。
- -n , --no-order执行在线 VACUUM FULL。从 1.2 版开始,这是非聚簇表的默认设置。
- -N , --dry-run列出将要重新包装并退出的内容。
- -j , –jobs创建指定数量的额外连接到 PostgreSQL,并使用这些额外连接并行重建每个表上的索引。并行索引构建仅支持全表重新打包,而不支持--index或--only-indexes选项。如果您的 PostgreSQL 服务器有额外的核心和磁盘 I/O 可用,这可能是加速pg_repack的有用方法。
- -s TBLSPC , --tablespace=TBLSPC将重新打包的表移动到指定的表空间:本质上是ALTER TABLE ... SET TABLESPACE的在线版本。表的索引保留在原始表空间中,除非也指定了--moveidx 。
- -S , --moveidx还将重新打包表的索引移动到--tablespace选项指定的表空间。
- -i , --index仅重新打包指定的索引。可以通过编写多个-i开关来重新打包多个索引。可以与 --tablespace结合使用以将索引移动到不同的表空间。
- -x , --only-indexes仅重新打包指定表的索引,必须使用--table或--parent-table选项指定。
- -T SECS , --wait-timeout=SECSpg_repack 需要在重组结束时获取独占锁。这个设置控制 pg_repack 等待获取这个锁的秒数。如果在这段时间后无法获取锁并且没有指定--no-kill-backend选项,pg_repack 将强制取消冲突的查询。如果您使用的是 PostgreSQL 8.4 或更新版本,pg_repack 将在两次超时后退回到使用 pg_terminate_backend() 来断开任何剩余的后端。默认值为 60 秒。
- -D , --no-kill-backend如果在指定的 --wait-timeout持续时间内无法获取锁,则跳到重新打包表 ,而不是取消冲突的查询。默认为假。
- -Z , --no-analyze全表重组后禁用 ANALYZE。如果未指定,则在重组后运行 ANALYZE。
- -k , --no-superuser-check跳过客户端中的超级用户检查。此设置对于在支持以非超级用户身份运行的平台上使用 pg_repack 很有用。
- -C , --exclude-extension跳过属于指定扩展名的表。某些扩展可能在计划时间等方面严重依赖于此类表。
连接选项
连接到服务器的选项。您不能同时使用--all
和--dbname
或 --table
或--parent-table
。
- -a , --all重组所有数据库。
- -d DBNAME ,--dbname=DBNAME指定要重组的数据库的名称。如果未指定且未使用-a(或--all),则从环境变量 PGDATABASE 中读取数据库名称。如果未设置,则使用为连接指定的用户名。
- -h HOSTNAME, --host=HOSTNAME指定运行服务器的机器的主机名。如果该值以斜杠开头,则它用作 Unix 域套接字的目录。
- -p PORT, --port=PORT指定服务器侦听连接的 TCP 端口或本地 Unix 域套接字文件扩展名。
- -U USERNAME, --username=USERNAME`连接的用户名。
- -w , --no-password永远不要发出密码提示。如果服务器需要密码身份验证,而密码无法通过其他方式(例如 .pgpass文件)获得,则连接尝试将失败。此选项在没有用户输入密码的批处理作业和脚本中很有用。
- -W , –password强制程序在连接到数据库之前提示输入密码。这个选项从来都不是必需的,因为如果服务器要求密码验证,程序会自动提示输入密码。然而,pg_repack 将浪费一次连接尝试来发现服务器需要密码。在某些情况下,值得键入
-W
以避免额外的连接尝试。
通用选项
- -e , –echo回声命令发送到服务器。
- -E LEVEL, --elevel=LEVEL从DEBUG、INFO、NOTICE、 WARNING、ERROR、LOG、FATAL和PANIC中选择输出消息级别。默认值为 信息。
- --help显示程序的使用情况。
- --version显示程序的版本号。
环境
PGDATABASE
,PGHOST
,PGPORT
,PGUSER
默认连接参数该实用程序与大多数其他 PostgreSQL 实用程序一样,也使用 libpq 支持的环境变量。
例子
对数据库test
中的所有聚簇表执行在线 CLUSTER
,并对所有 非聚簇表执行在线 VACUUM FULL
:
[postgres@lyp ~]$ pg_repack test
INFO: repacking table "public.t1"
INFO: repacking table "public.t2"
[postgres@lyp ~]$
对数据库测试中的表foo
和bar
执行在线 VACUUM FULL
(忽略最终的集群索引):
[postgres@lyp ~]$ pg_repack --no-order --table t1 --table t2 test
INFO: repacking table "public.t1"
INFO: repacking table "public.t2"
[postgres@lyp ~]$
将表foo
的所有索引移动到表空间lxs
:
test=# select * from pg_indexes where tablename='t1';
schemaname | tablename | indexname | tablespace | indexdef
------------+-----------+-----------+------------+------------------------------------------------------------
public | t1 | pk_t2_id | | CREATE UNIQUE INDEX t1_pkey ON public.t1 USING btree (id)
(1 row)
test=# \q
[postgres@lyp ~]$ pg_repack -d test --table foo --only-indexes --tablespace lxs
INFO: repacking indexes of "t1"
INFO: repacking index "pub
[postgres@lyp ~]$
[postgres@lyp ~]$ psql -d test
psql (13.2)
Type "help" for help.
test=#
test=# select * from pg_indexes where tablename='t1';
schemaname | tablename | indexname | tablespace | indexdef
------------+-----------+-----------+------------+-----------------------------------------------------------
public | t1 | t1_pkey | lxs | CREATE UNIQUE INDEX t1_pkey ON public.t1 USING btree (id)
(1 row)
test=#
将指定的索引移动到表空间lxs
:
test=# select * from pg_indexes where tablename='t2';
schemaname | tablename | indexname | tablespace | indexdef
------------+-----------+-----------+------------+------------------------------------------------------------
public | t2 | pk_t2_id | | CREATE UNIQUE INDEX pk_t2_id ON public.t2 USING btree (id)
(1 row)
test=# \q
[postgres@lyp ~]$ pg_repack -d test --index pk_t2_id --tablespace lxs
INFO: repacking index "public.pk_t2_id"
[postgres@lyp ~]$ psql -d test
psql (13.2)
Type "help" for help.
test=# select * from pg_indexes where tablename='t2';
schemaname | tablename | indexname | tablespace | indexdef
------------+-----------+-----------+------------+------------------------------------------------------------
public | t2 | pk_t2_id | lxs | CREATE UNIQUE INDEX pk_t2_id ON public.t2 USING btree (id)
(1 row)
test=#
诊断
pg_repack
失败时会报告错误消息。下面的列表显示了错误的原因。
您需要在发生致命错误后手动清理。要清理,只需从数据库中删除 pg_repack 并重新安装:对于 PostgreSQL 9.1 及以后的版本,在发生错误的数据库中执行DROP EXTENSION pg_repack CASCADE ,然后执行``CREATE EXTENSION pg_repack;对于以前的版本,将脚本$SHAREDIR/contrib/uninstall_pg_repack.sql加载到发生错误的数据库中,然后再次加载 $SHAREDIR/contrib/pg_repack.sql。
- INFO: database "db" skipped: pg_repack 1.4.8 is not installed in the database当指定--all选项时,pg_repack 不会安装在数据库中。在数据库中创建 pg_repack 扩展。
- ERROR: pg_repack 1.4.8 is not installed in the databasepg_repack 没有安装在--dbname指定的数据库中。在数据库中创建 pg_repack 扩展。
- ERROR: program 'pg_repack V1' does not match database library 'pg_repack V2'pg_repack二进制文件和数据库库(.so或.dll)之间存在不匹配。不匹配可能是由于$PATH中的错误二进制文件或正在寻址的错误数据库。检查程序目录和数据库;如果它们符合预期,您可能需要再次对pg_repack 进行安装。
- ERROR: extension 'pg_repack V1' required, found 'pg_repack V2'在数据库中找到的 SQL 扩展与 pg_repack 程序所需的版本不匹配。您应该从数据库中删除扩展并按照安装部分中的描述重新加载它。
- ERROR: relation "table" must have a primary key or not-null unique keys目标表没有定义 PRIMARY KEY 或任何 UNIQUE 约束。在表上定义 PRIMARY KEY 或 UNIQUE 约束。
- ERROR: query failed: ERROR: column "col" does not exist目标表没有由--order-by选项指定的列。指定现有列。
- WARNING: the table "tbl" already has a trigger called repack_trigger触发器可能是在先前尝试在表上运行 pg_repack 时安装的,该表被中断并且由于某种原因未能清理临时对象。您可以通过删除并重新创建扩展来删除所有临时对象。
- ERROR: Another pg_repack command may be running on the table. Please try again later.当两个并发的 pg_repack 命令在同一个表上运行时,可能会出现死锁。因此,尝试在一段时间后运行该命令。
- WARNING: Cannot create index "schema"."index_xxxxx", already exists详细信息: 中断的表上的先前 pg_repack 可能留下了无效索引。请使用 DROP INDEX “schema”.“index_xxxxx” 删除该索引并重试。显然由 pg_repack 创建的临时索引已被遗忘,我们不想冒险自己删除该索引。如果索引实际上是由一个没有被清理的旧 pg_repack 作业创建的,你应该只使用DROP INDEX并再次尝试 repack 命令。
限制
pg_repack
有以下限制。
临时表
pg_repack
不能重组临时表。
GiST 索引
pg_repack
不能通过 GiST 索引聚集表。
DDL 命令
当 pg_repack
工作时,您将无法执行目标表的 DDL 命令,除了VACUUM
或 ANALYZE
。pg_repack
将在全表重新打包期间在目标表上持有一个 ACCESS SHARE
锁,以强制执行此限制。
细节
Full Table Repacks
要执行full-table repack,pg_repack
将:
- 创建一个日志表来记录对原始表所做的更改
- 在原始表上添加触发器,将
INSERT
、UPDATE
和DELETE
记录到我们的日志表中 - 创建一个包含旧表中所有行的新表
- 在这个新表上建立索引
- 将日志表中产生的所有更改应用到新表
- 使用系统目录交换表,包括索引和 toast 表
- 删除原始表
pg_repack
只会在初始设置(上面的第 1 步和第 2 步)和最后的交换和删除阶段(第 6 步和第 7 步)期间持有一个 ACCESS EXCLUSIVE
锁一小段时间。在剩下的时间里,pg_repack
只需要在原始表上持有一个 ACCESS SHARE
锁,这意味着 INSERT
、UPDATE
和 DELETE
可以照常进行。
Index Only Repacks
要执行index-only repack,pg_repack
将:
- 使用
CONCURRENTLY
匹配旧索引的定义在表上创建新索引 - 将目录中的旧索引换成新索引
- 删除旧索引
安装 pg_repack rpm 方式
root用户下:
rpm -ivh pg_repack_12-1.4.8-1.rhel7.x86_64.rpm
##登录数据库
Create extension pg_repack;
##确认是否安装完成
select * from pg_extension;
##查询到对应扩展表示安装成功
示例
pg_repack -p 15432 -d testdb -t schema_name.table_name
表膨胀查询
建议:核心表膨胀率不超过80%
select stt.schemaname, stt.relname, pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size( stt.relid )) as "Rel_Size",
t.relpages * 8 / 1024 page_size_mb , round(avg_width * t.reltuples::NUMERIC / 1024/1024) data_size_mb,
case when t.relpages * 8 > avg_width * t.reltuples::NUMERIC / 1024 then
round((( t.relpages * 8 ) - (avg_width * t.reltuples::NUMERIC / 1024))::NUMERIC *100 / nullif((avg_width * t.reltuples::NUMERIC / 1024),0) , 2)
else null end expand_ratio,
t.relpages, t.reltuples::NUMERIC,
n_dead_tup , n_live_tup,
round(n_dead_tup* 100 / nullif(n_live_tup + n_dead_tup, 0) , 2) dead_tup_ratio ,
COALESCE( stt.last_analyze, stt.last_autoanalyze ) last_analyze
from pg_stat_all_tables stt, pg_class t , ( select sum(avg_width) avg_width ,schemaname,tablename from pg_stats group by schemaname,tablename ) st
where stt.relid = t.oid
and stt.schemaname = st.schemaname and stt.relname = st.tablename
and t.relpages * 8 > 100 * 1024
order by expand_ratio desc nulls last
limit 50;